You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何检测Ruby脚本关闭状态并禁用WebSocket重连?Signal.trap无效求助

解决Ruby脚本关闭时停止WebSocket重连的问题

我来帮你梳理下问题所在,以及对应的解决方案:

问题分析

你遇到的几个核心问题:

  1. 信号监听错配:按下CTRL-C发送的是INT信号,不是TERM信号,所以之前监听TERM自然不会触发。
  2. 信号陷阱设置时机滞后:你在ws_closed方法里才注册信号陷阱,但这个方法只有当WebSocket连接关闭时才会执行,程序退出时可能连接还没断开,陷阱根本没被注册上。
  3. 实例变量封装限制:@reconnect是类内部的实例变量,外部直接修改违反封装原则,也没法直接访问。

解决方案

我们可以通过封装停止方法+提前注册多信号监听+**结合at_exit**来解决:

1. 给WebsocketClient添加停止重连的方法

在类内部封装修改实例变量的逻辑,提供一个对外的接口:

class WebsocketClient
  def initialize
    @reconnect = true
    @stop = false
    @reconnect_after = 5 # 根据你的实际需求调整
  end

  # 新增:对外暴露停止重连的方法
  def stop_gracefully
    @reconnect = false
    @stop = true
    # 确保EventMachine事件循环停止(如果还在运行)
    EM.stop if EM.reactor_running?
    $logger.warn "WebSocket reconnect disabled, stopping event loop..."
  end

  def ws_closed(event)
    $logger.warn "WS CLOSED"
    if @stop
      EM.stop
    elsif @reconnect
      $logger.warn "Reconnecting..."
      EM.add_timer(@reconnect_after){ connect! }
    end
  end

  # 假设你的连接方法
  def connect!
    # 这里写你的WebSocket连接逻辑
  end
end

2. 在脚本初始化阶段注册信号监听

在创建WebsocketClient实例之后,立即监听INT(CTRL-C)和TERM(kill命令)信号:

# 创建客户端实例
client = WebsocketClient.new

# 监听退出信号
["INT", "TERM"].each do |signal|
  Signal.trap(signal) do
    $logger.warn "Received #{signal} signal, initiating graceful shutdown..."
    client.stop_gracefully
    # 触发at_exit逻辑后退出
    exit
  end
end

3. 完善at_exit块

确保即使信号监听没触发(比如程序正常结束),也能调用停止方法:

at_exit {
  $logger.fatal "Application terminated. Shutting down gracefully..."
  # 检查client是否存在,避免未初始化的情况
  client.stop_gracefully if defined?(client)
  # 其他退出清理工作...
}

为什么这样有效?

  • 信号监听覆盖全面:同时监听INT和TERM,覆盖了手动按CTRL-C和通过kill命令终止程序的场景。
  • 封装符合原则:通过类方法修改内部实例变量,既保证了数据安全,又提供了对外操作的接口。
  • 时机正确:信号陷阱在程序启动时就注册,无论程序何时退出都能触发。

内容的提问来源于stack exchange,提问作者Ilya Cherevkov

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.19 03:16:50