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

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

楼主现在做一个组件发布平台,其中需要用到 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 执行后调用

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