Задать вопрос
@justed_ss
ewf

Как правильно реализовать SSE в RAILS?

Нужно чтобы несколько клиентов слушали метод, который отправлял в случае изменения/создания записи, эту самую запись в виде JSON.

Rails 4. бд - postgresql, сервер Puma
В интернете полно бесполезных инструкций где метод отправляет с интервалом что-либо а потом закрывает соединение. Либо пишут middleware/модуль в lib который в обход роутов/контроллеров/авторизации выполняет полезный функционал, но это все выглядит как костыль.

Нашел что то похожее на то что нужно, но там тоже не все так гладко

Контроллер
def index
  response.headers['Content-Type'] = 'text/event-stream'
  sse = SSE.new(response.stream)
  begin
    Comment.on_change do |data|
      sse.write(data)
    end
  rescue IOError
    # Client Disconnected
  ensure
    sse.close
  end
  render nothing: true
end


Метод on_change. Событие из бд тригерится в стандартных калбеках Rails
def on_change
    Comment.connection.execute "LISTEN comments"
    loop do
      Comment.connection.raw_connection.wait_for_notify do |event, pid, comment|
        yield comment
      end
    end
ensure
  Comment.connection.execute "UNLISTEN comments"
end


Но сервер после нескольких коннектов повисает где то на этапе ожидания ивента из бд. Пробовал больше воркеров, результат не сильно изменился. Ну и судя по всему он каждый раз держит отдельное соединение с бд в ожидании ивента отчего ActiveRecord временами уходит в таймаут.

В общем вопрос, где почитать/посмотреть "полезную" реализацию sse?
  • Вопрос задан
  • 847 просмотров
Подписаться 3 Средний Комментировать
Пригласить эксперта
Ответы на вопрос 2
@fuCtor
Ruby разработчик
С SSE есть нюанс, если используете не событийный сервер приложений (unicorn, puma и тд), то каждый запрос будет блокировать один из потоков/процессов. Со временем они закончатся и выполнение всего встанет на ожидании БД либо еще чего блокирующего.

Лучше всего использовать Thin, он построен на EventMachine и не вызывает блокирования внешнего запроса, но может быть заблокирован запросом к БД.

У себя делал такую связку:
Sinatra + Sinatra-SSE монтируется в Rails для приема подключений. Слушание событий (PG, Redis и тд) делается на EM совместимых клиентах. И заводится некоторый менеджер подключений который будет рассылать данные.

Как-то так.
Ответ написан
Комментировать
@khataev
Есть вот такой вариант
Ответ написан
Комментировать
Ваш ответ на вопрос

Войдите, чтобы написать ответ

Похожие вопросы