0

我想SSE功能添加到使用的Redis PubSub的我的服务器应用程序,通过多篇文章指导即: how-to-use-actioncontollerlive-along-with-resque-redis无法处理断开连接的客户SSE

服务器中的Heroku托管,从而心跳是必要的,以及。

... 
sse = SSE.new(response.stream) 
begin 
    redis = Redis.new(:url => ENV['REDISCLOUD_URL']) 
    redis.subscribe(<UUID>, HEARTBEAT_CHANNEL) do |on| 
     on.message do |channel, data| 
      begin 
       if channel == HEARTBEAT_CHANNEL 
        sse.write('', event: "hb") 
       else 
        sse.write(data, event: "offer_update") 
       end 
      rescue StandardError => e #I'll call this section- "internal rescue" 
       puts "Internal: #{$!}" 
       redis.quit 
       sse.close 
       puts "SSE was closed 
      end 
     end 
    end 
rescue StandardError => e #I'll call this section- "external rescue" 
    puts "External: #{$!}" 
ensure 
    redis.quit 
    sse.close 
    puts "sse was closed" 
end 

的问题:

  1. 我没有看到任何地方的 “内部救助” 过网谈SSE。但是如果由sse.write引发,我不会得到哪些人可以发现异常?常见的情况是HB发送时客户端不再连接,这使得这部分非常关键(出现"Internal: client disconnected")。我对吗?
  2. 在这种情况下,将“外部救援”被触发?客户端断开是否导致sse.write在“内部块”(on.message内部)中引发异常?因为当我试图模拟它几十次时,它从未被外部救援所捕获。
  3. 此代码也受到影响。内部营救部分的redis.quit引发了另一个由外部营救声明捕获的异常:External: undefined method 'disconnect' for #<Redis::SubscribedClient:0x007fa8cd54b820>。所以 - 它应该怎么做?我如何才能识别客户端断开,以释放内存&套接字?
  4. 怎么能够由sse.write引起的异常没有被外部救援陷入(因为它应该是从开始),而另一个错误(我的第三个问题中所述)已经被抓住?所有这些代码(outer + inner部分)都在同一个线程中运行,对吧?我很乐意进行深入的解释。

回答

0

您发现subscribe中的异常,因此redis不知道它,并且不会正确地停止它的内部循环。 redis.quit将导致它崩溃并停止,因为它不能等待消息。这显然不是一个好办法。

如果您的代码在subscribe内部抛出异常,它将导致redis优雅地取消订阅,您的异常可以在外部获救,如在“外部救援”中。

另一点是,你不应该没有充分处理它们捕获异常,你永远不应该赶上一般例外,而无需重新认识他们。在这种情况下,您可以安全地让ClientDisconnected异常冒泡到Rails的代码中。

这是你的控制器的代码应该如何看起来像:

def subscribe 
    sse = SSE.new(response.stream) 
    redis = Redis.new(:url => ENV['REDISCLOUD_URL']) 
    redis.subscribe(<UUID>, HEARTBEAT_CHANNEL) do |on| 
    on.message do |channel, data| 
     if channel == HEARTBEAT_CHANNEL 
     sse.write('', event: "hb") 
     else 
     sse.write(data, event: "offer_update") 
     end 
    end 
    end 
ensure 
    redis.quit if reddis # might not have had a chance to initialize yet 
    sse.close if sse # might not have had a chance to initialize yet 
    puts "sse was closed" 
end 
相关问题