我尝试使用Redis PubSub将SSE功能添加到我的服务器应用程序,在许多文章的指导下,即: how-to-use-actioncontollerlive-along-with-resque-redis
服务器托管在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
问题:
sse.write
提出异常,我不知道谁能抓到异常?常见的情况是在客户端不再连接时发送HB,这使得该部分非常关键("Internal: client disconnected"
出现)。我是对的吗?sse.write
在&#34;内部块中引发异常&#34; (在on.message机构内)?因为当我试图模拟它几十次时它从未被外部救援抓住。redis.quit
引发了另一个由外部救援声明捕获的异常:External: undefined method 'disconnect' for #<Redis::SubscribedClient:0x007fa8cd54b820>
。那么 - 应该怎么做?我如何识别ASAP客户端断开以释放内存和插座?sse.write
引发的异常怎么可能没有被外部救援抓住(因为它应该从一开始就被捕获)而另一个错误(在我的第三个问题中描述)已经被抓住了?所有这些代码(外部+内部部分)都在同一个线程中运行,对吧?我很乐意深入解释。答案 0 :(得分:0)
你在subscribe
内捕获了异常,因此redis不知道它并且不会正确地停止它的内循环。 redis.quit
会导致崩溃并停止,因为它无法等待消息。这显然不是一个很好的方法。
如果您的代码在subscribe
内引发异常,则会导致redis正常取消订阅,并且您的例外可以在外部获救,例如在您的&#34;外部救援&#34;。
另一点是,你不应该在没有完全处理它们的情况下捕获异常,并且你不应该在不重新提升它们的情况下捕获一般异常。在这种情况下,您可以放心地将ClientDisconnected
异常气泡转移到Rails&#39;代码。
以下是您的控制器代码的外观:
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