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 
相關問題