Sinatra Sinatra 和 Sidekiq 如何访问同个 websocket 连接?

tripleCC · 2018年10月17日 · 最后由 jimrokliu 回复于 2018年10月22日 · 4381 次阅读

楼主现在做一个组件发布平台,其中需要用到 websocket 同步组件的发布状态到 Web,这里我用的是 em-websocket。

由于用到的功能不多,我直接开新的线程在 Sinatra 进程里面初始化 websocket 了,初始化代码如下

Thread.new do 
 EM.run do 
   signature = EventMachine::WebSocket.start(
     :host => '0.0.0.0', 
     :port => Labor.config.websocket_port, 
     :debug => false#!Sinatra::Base.settings.production?
     ) do |ws|
     ws.onopen do |handshake|
       catch_logger do 
         query = CGI::parse(handshake.query_string)
         deploy_id = query['id']&.first

         Labor::DeployMessager.push_ws(deploy_id, ws)
         logger.info("open socket #{ws} with deploy id #{deploy_id}")
       end
     end
     ....
   end
   # EM.stop_server signature
 end
end

当 Web 点击开发发布时,Sinatra 会处理这个请求,并且去 Labor::DeployMessager 保存的 websockets 数组中找对应的 websocket ,发送状态信息。后续 GitLab 会触发 webhook,Sinatra 处理之后也会通过 websocket 通过给 Web 。

但是在使用 Sidekiq 将 GitLab 触发 webhook 的任务放到后台后(这个任务比较耗时,可能要十几秒),发现由于 Sidekiq 和 Sinatra 读取执行了两次代码,上面保存的 websockets 在 Sidekiq 里面访问不了。 楼主做客户端的 ,对后台的这些服务不是很了解,想问下这种情况下,怎么处理两个服务都要通过 websocket 向 Web 同步状态的情况?

Sinatra 进程里面初始化 websocket

这个初始化是在应用启动时还是在接受 http 请求时?

我可以这样理解你的需求吗?

               |====>Sinatra
websocket ====>|
               |====>Sidekiq

后台任务通过某种消息机制(例如 Redis pubsub)通知管理 websockets 的进程,再由管理 websockets 的进程通知用户。

Rails 里的 ActionCable 实现了这个机制 https://guides.rubyonrails.org/action_cable_overview.html

a-wing 回复

是启动时初始化的,可以这么理解。 Sinatra 和 Sidekiq 两个不同服务

Rei 回复

多谢多谢,我先去了解下这块内容。由于我没有 rails ,要实现类似 ActionCable 的功能,我是否需要把 websockets 这块服务从原先 web server 里面剥离出来,单独成独立的 websocket server ,然后再通过 redis 进行通信呢?

你需要在 Sinatra 上提供一个 REST 接口,让 Sidekiq 执行后调用

需要 登录 后方可回复, 如果你还没有账号请点击这里 注册