Яндекс.Метрика

    Песочница

    NodeJS + SMPP и очередь сообщений Memcacheq

    Возникла необходимость реализовать отправку и прием сообщений по протоколу smpp, и делать это нужно было с расчетом на высокий трафик и с возможностью простого взаимодействия с другими приложениями.
    В процессе выбора платформы было решено использовать NodeJS.
    Почему NodeJS? Что за зверь Memcacheq?

    Почему nodeJs?


    Потому как это простой способ быстро написать асинхронный демон не тратя силы на реализацию различных служебных методов взаимодействия с другими приложениями, базами данных и т.п…
    Так же на выбор повлияло наличие готовой (хоть и не полноценной) библиотеки для работы с smpp на nodeJS — Shorty.

    Первым делом решили протестировать работу этой библиотеки. В процессе тестирования были найдены некоторые приятные бонусы. К ним можно отнести то, что shorty может работать в трех режимах: Transmitter, Receiver, Transceiver (передатчик, приемник, приемопередатчик соотв.). Это позволяет его использовать не только для отправки сообщений, но и как smpp сервер к которому будут подключаться клиенты (конечно это только малая часть возможностей smpp протокола).
    Но есть и неприятные моменты. Shorty не работает с «склеенными» сообщениями (когда текст смс длинной более 140 байт делится на несколько коротких сообщений, с присоединением служебной информации). Так же shorty работает только с кодировкой GSM03.38, GSM03.40 (для кодирования текста в формате отличном от GSM используется кодировка UCS-2) что естественно не включает в себя кириллический текст.

    Так как Shorty нам показался привлекательным решением, мы приступили к его «допиливанию». Процесс был весьма увлекательным. Для доработки пришлось подключить библиотеку iconv. Благо код shorty организован весьма логично, и разбираться в нем было одно удовольствие, и доработки много времени не потребовали (скачать исходники можно по ссылке в конце статьи).

    После того, как мы подправили напильником shorty, можно было продолжать реализовывать наш коварный план.
    Для реализации очереди сообщений мы решили использовать memcacheq это open source решение для организации очередей основанный на memcache и Berkeley DB. В его пользу было то, что memcacheq позволяет решить вопросы мульти-очереди, конкурентных запросов, и общего интерфейса для различных программных сред. Подробнее про memcacheq можно почитать тут.

    Теперь подробнее о том как это все работает


    Под управлением nodeJS запущен скрипт, который держит постоянное подключение с smpp и memcacheq. Скрипт периодически (по таймауту) опрашивает очередь на наличие в ней элементов. Если в очереди появляются сообщения, мы их отправляем на шлюз (при выполнении запроса get к memcacheq элемент убирается из очереди), в случае успеха, вызывается колбэк который обновляет статус сообщения (у нас это хранится в mysql базе) при неудаче, сообщение обратно отправляется в очередь (методом set мы ставим сообщение в конец очереди) и продолжаем работу.

    Вроде все просто и логично. Но! Всегда есть но!
    1. При разрыве соединения с smpp или memcacheq нужно заново подключатся
    2. При разрыве соединения возможны выбросы исключений NodeJS (к примеру таймаут сокета или не выбранная база данных после реконекта к mysql и т. п.). А при выбросе исключения, процесс останавливается, что очень плохо в такой ситуации

    Первый пункт решается довольно просто. При разрыве соединения, например shorty вызывает событие, на которое можно повесить колбэк функцию.
    Со вторым пунктом не все так просто. Конечно нужно писать код так, чтобы все исключения отлавливать и не давать им убивать процесс. Но подстраховаться никогда не лишне.
    Для обработки такой ситуации есть весьма простая и интересная NodeJS библиотека «supervisor». Наш скрипт запускаем при помощи этой библиотеки, и она отловит «убивание» процесса, и самостоятельно запустит его заново.

    Что в итоге мы получили?


    Быстрый шлюз для работы с smpp используя очереди. Асинхронный демон для работы с очередями.
    Связку memcacheq+nodeJS можно использовать и для решения других задач, и при необходимости масштабировать. Так же можно довольно просто реализовать работу с очередями в многопоточном режиме, использую несколько воркеров на nodeJS, но это тема для другой статьи.

    Всем спасибо за внимание.
    Отдельно спасибо хабраюзеру PycmaM за советы по реализации и работе с протоколом smpp.

    ссылки на проекты упоминающиеся в тексте:
    nodejs.org
    memcachedb.org/memcacheq
    github.com/mtd/shorty
    github.com/elbart/node-memcache
    github.com/isaacs/node-supervisor
    github.com/bnoordhuis/node-iconv

    Исходные коды и пример реализации.