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

Mojolicious+Hypnotoad:Worker超时关闭前如何通知客户端?

解决方案

针对Mojolicious + Hypnotoad环境下,Worker超时关闭前通知客户端的需求,可通过以下步骤实现:

核心思路

  1. 跟踪当前活跃的客户端连接(WebSocket/HTTP长连接)
  2. 利用before_server_start钩子监听Worker的finish事件,在Worker退出前遍历活跃连接发送通知

代码实现

sub startup {
  my $self = shift;

  # 每个Worker独立维护活跃连接集合(多进程模型下无需跨进程同步)
  my $active_connections = {};

  # 注册服务器启动前钩子,绑定Worker退出事件
  $self->hook(before_server_start => sub {
    my ($server, $app) = @_;

    # Worker即将退出时触发finish事件
    $server->on(finish => sub {
      my $server = shift;

      # 遍历所有活跃连接发送关闭通知
      foreach my $tx (values %$active_connections) {
        next unless $tx->is_websocket || $tx->keep_alive;

        # WebSocket连接处理:发送通知后主动关闭
        if ($tx->is_websocket) {
          $tx->send({ text => 'Worker因超时即将关闭,请重新连接。' });
          $tx->finish;
        }
        # HTTP长连接(如SSE)处理:返回503并关闭连接
        elsif (!$tx->res->code) {
          $tx->res->code(503);
          $tx->res->body('Worker因超时即将关闭,请稍后重试。');
          $tx->res->headers->connection('close');
          $tx->send;
        }
      }

      # 清空连接集合,避免内存泄漏
      %$active_connections = ();
    });
  });

  # WebSocket示例路由
  $self->routes->websocket('/api/ws')->to(cb => sub {
    my $c = shift;
    my $tx_id = $c->tx->id;

    # 将当前连接加入活跃集合
    $active_connections->{$tx_id} = $c->tx;

    # 连接关闭时从集合移除
    $c->tx->on(finish => sub {
      delete $active_connections->{$tx_id};
    });

    # 此处添加WebSocket业务逻辑...
  });

  # SSE长连接示例路由
  $self->routes->get('/api/sse')->to(cb => sub {
    my $c = shift;
    my $tx_id = $c->tx->id;

    # 设置SSE响应头
    $c->res->headers->content_type('text/event-stream');
    $c->res->headers->cache_control('no-cache');
    $c->res->headers->connection('keep-alive');

    # 将当前连接加入活跃集合
    $active_connections->{$tx_id} = $c->tx;

    # 连接关闭时从集合移除
    $c->tx->on(finish => sub {
      delete $active_connections->{$tx_id};
    });

    # 发送初始连接确认
    $c->write("data: 连接已建立\n\n");

    # 此处添加SSE业务逻辑...
  });
}

关键说明

  • 多进程适配:Hypnotoad采用多进程模型,每个Worker独立维护$active_connections,无需考虑跨进程数据同步问题。
  • 事件时机:finish事件在Worker进入优雅关闭阶段触发,此时仍可操作事件循环发送响应,避免了END块、析构函数或信号处理的时机问题。
  • 连接清理:必须在连接关闭时从集合中移除对应tx对象,防止内存泄漏。

为什么之前的方案无效?

  • 控制器析构函数:仅在对象销毁时触发,Worker关闭时控制器可能已被回收,无法关联到活跃连接。
  • END块:进程退出时执行,但此时Mojolicious事件循环已停止,无法发送响应。
  • 信号处理:Hypnotoad会捕获STOP/QUIT信号并处理优雅关闭,自定义信号处理会干扰默认逻辑,且信号处理函数中无法安全操作事件循环。

内容的提问来源于stack exchange,提问作者Fausto B.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 17:23:09