Как закрыть соединение Redis с помощью потокового API Sinatra? - PullRequest
3 голосов
/ 20 декабря 2011

У меня есть следующее приложение sinatra:

require 'sinatra'
require 'redis'
require 'json'


class FeedStream < Sinatra::Application


  helpers do
    include SessionsHelper

    def redis
      @redis ||= Redis.connect
    end
  end

  get '/feed', provides: 'text/event-stream' do


    stream do |out|

      redis.subscribe "feed" do |on|

        on.message do |channel, message|
          event_data = JSON.parse message
          logger.info "received event = #{event_data}"
          out << "event: #{event_data['event']}\n"
          out << "data: #{{:data => event_data['data'],
                           :by => current_user}}.to_json\n\n"
        end
      end
    end

  end

end

По сути, он получает события, опубликованные другими пользователями, в канал, используя redis pubsub, а затем отправляет эти события с помощью потокового API-интерфейса sinatra. Проблема заключается в том, что при повторном подключении браузера к каналу клиент redis остается подключенным и продолжает получать события, поэтому сервер redis заполняется бесполезными подключениями. как я могу закрыть все эти соединения, когда броузер закрывает соединение с веб-сервером?

Ответы [ 2 ]

1 голос
/ 08 апреля 2014

После долгих исследований и экспериментов, вот код, который я использую с sinatra + sinatra sse gem (который должен быть легко адаптирован к Rails 4):

class EventServer < Sinatra::Base
 include Sinatra::SSE
 set :connections, []
 .
 .
 .
 get '/channel/:channel' do
 .
 .
 .
  sse_stream do |out|
    settings.connections << out
    out.callback {
      puts 'Client disconnected from sse';
      settings.connections.delete(out);
    }
  redis.subscribe(channel) do |on|
      on.subscribe do |channel, subscriptions|
        puts "Subscribed to redis ##{channel}\n"
      end
      on.message do |channel, message|
        puts "Message from redis ##{channel}: #{message}\n"
        message = JSON.parse(message)
        .
        .
        .
        if settings.connections.include?(out)
          out.push(message)
        else
          puts 'closing orphaned redis connection'
          redis.unsubscribe
        end
      end
    end
  end
end

Соединение redis блокирует on.message и принимает только команды (p) подписки / (p) отмены подписки. После того как вы отмените подписку, соединение redis больше не блокируется и может быть освобождено объектом веб-сервера, для которого был создан первоначальный запрос sse. Он автоматически очищается, когда вы получаете сообщение о переадресации, и sse-соединение с браузером больше не существует в массиве коллекции.

1 голос
/ 19 июля 2012

Я знаю, что это было давно.

Вы искали бросить ?

...