Обычно при запросе можно получить объект с сокетом и что-то делать (у меня express с socket.io). Но, если например, у меня есть крон-джоба, которая запускается раз в час и что-то делает, потом она хочет оповестить всех приконнекченых клиентов (emit), но реквеста не было, и получить сокет некак. Глобальные переменные использовать - совсем не вариант я думаю. При запуске приложения таким образом - app.set('io', io);, сеттим сокет где io содержит основные события и авторизацию сокет-клиентов. Как можно решить такую задачу не используя реквест?
тогда нужно заводить отдельный сторедж для соединений и добавлять их туда при каждом подключении. а связывать крон-джобу с express-сервером нужно через какой-то интерфейс. мне в голову приходит RabbitMQ
Я использую io.adapter(redis({host: h, port: p})); т.к. для работы в кластере он необходим для socket.io.
Вы можете подробнее рассказать, примеры может?
Alexander K.: плотно с socket.io я не работал. я работал с нативной реализацией веб-сокетов в ноде. вот что я имею в виду
вы запускаете веб-сокет сервер. когда кто-то коннектится к веб-сокет серверу вы можете получить соединение. некий объект, который инкапсулирует соединение с клиентом. вы можете отправить что-то на это соединение - оповестить клиента. вы можете завести сторедж, в котором храните все соединения, такой себе массив. когда кто-то подключается к серверу - вы кладете в этот массив объект-соединение. когда кто-то отключается - вы удаляете из него это соединение.
теперь берем RabbitMQ. это такой себе сервер очередей, который принимает сообщения на одном конце и отдает из на другом конце. там много всего интересного, но нам все не нужно. нам важно то, что он слушает одним концом и говорит другим концом. итак, вы запускаете веб-сокет сервер, он работает, принимает соединения и дополнительно слушает RabbitMQ сервер. если он что-то от него получает (там тоже на событиях завязано), то он что-то делает. запомним этот момент.
с другой стороны у вас есть крон-джоба, которая когда-то там запускается. неважно когда, важно, что она запускается. при запуске этой джобы вы можете обратиться к RabbitMQ серверу и сказать ему что-то (он слушает), он примет это и передасть это дело на веб-сокет сервер, который слушает этот же RabbitMQ сервер.
возвращаемся к веб-сокет серверу: он что-то услышал от RabbitMQ сервера (например, нужно что-то броадкастить на все соединения), он берет данные, которые узнал от RabbitMQ сервера, берет все соединения из стореджа (помните тот массив, в который мы складировали соединения?) и отправляет это каждому соединению.
приблизительно так я предлагаю Вам сделать. в socket.io есть broadcast на все активные соединения и потому, возможно, не нужно складировать в отдельный сторедж, но это не суть. вам нужно как-то связать крон-джобу с работающим веб-сервером. я предлагаю вам использовать RabbitMQ сервер. можно обойтись и без него, выделив для этого отдельный канал в socket.io сервере, коннектиться к нему из крон-джобы и отправлять на него свое сообщение. может еще можно повесить аунтентификацию на этот канал (я не помню уже как там с этим в socket.io). так будет даже безопаснее
Дмитрий Вапельник: спасибо, очень полезная информация! Но я уже сделал немного по-другому, через redis-storage, и в класс который порождает кронджобы (в мастере) я передал объект сокет-сервера, и теперь каждая кронджоба себе наследует его, и благодаря redis-store я из джобы делаю emit, и данные получают клиенты на всех воркерах. Все работает на ура)
Alexander K.: самый лучший вариант это push уведомления. Правда тут я подсказать не могу, так как не делал ни разу. push уведомления это не только для мобильных. По сути это тот же websocket сервер, на который откуда угодно отправляются нотификации через http апи, а клиент их сразу получает(если он онлайн) и если подписан на канал нужный.
Где-то видел на гитхабе, но уже не найду.
subscribe publish ключевые слова.
Александр Аксентьев: спасибо, рассмотрю этот вариант. Но думаю, в моем случае все же лучше всего как-то расшарить все сокет соединения чтобы были доступны в любом месте , пока только не пойму как.
Alexander K.: вне сервера никак) По сути только использовать схему как выше привел, можно самописный вариант сделать простой, в любом случае только один этот вариант возможен.
Дмитрий Вапельник: если не ошибаюсь в MongoDB есть механизм для подписки на новые документы. Вполне себе отличный вариант, чекать самому не надо, а только подписаться в базе на обновления коллекции.