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

Node.js Express中基于Socket.io的异步任务手动取消实现方案

解决方案:无需子进程实现异步任务的手动终止

核心思路

抛弃child_process创建独立进程的方案,改用AbortController(Node.js 15+原生支持)或自定义终止标志,在异步任务的关键执行节点检查终止信号,实现优雅中断,彻底避免额外的进程内存开销。

具体实现步骤

1. 维护任务终止控制器映射表

在服务器端全局维护一个Map,关联每个任务的uid与对应的终止控制器:

// 全局存储任务终止控制器,key为任务uid,value为AbortController实例
const taskControllers = new Map();

2. 修改任务启动逻辑

客户端触发tasks:launch时,创建AbortController并存储,将终止信号传入任务函数:

socket.on('tasks:launch', ({ uid, data }) => {
  const controller = new AbortController();
  const signal = controller.signal;
  taskControllers.set(uid, controller);

  (async () => {
    try {
      await collector_obj.tasks.task(uid, data, io, signal);
    } catch (err) {
      // 捕获终止信号触发的错误,属于正常终止无需额外处理
      if (err.message !== '任务已终止') {
        console.error(`任务 ${uid} 执行出错:`, err);
      }
    } finally {
      // 任务结束后清理控制器,避免内存泄漏
      taskControllers.delete(uid);
    }
  })();
});

3. 改造任务函数支持终止

在任务的每个异步步骤检查终止信号,或使用支持AbortSignal的API:

task: async (uid, data, io, signal) => {
  const sleep = (ms, signal) => new Promise((resolve, reject) => {
    const timer = setTimeout(resolve, ms);
    // 监听终止信号,触发时清除定时器并抛出终止错误
    signal.addEventListener('abort', () => {
      clearTimeout(timer);
      reject(new Error('任务已终止'));
    });
  });

  while (true) {
    // 每次循环前检查是否已触发终止
    if (signal.aborted) {
      throw new Error('任务已终止');
    }

    await sleep(1000, signal);
    console.log(Date.now());

    // 数据库操作场景:优先用支持AbortSignal的驱动(如pg@8.8+、mongoose@6.8+)
    // 示例:PostgreSQL查询结合终止信号
    // await pgClient.query('SELECT * FROM target_table', [], { signal });

    // 若驱动不支持,手动在操作前后检查终止状态
    // if (signal.aborted) throw new Error('任务已终止');
    // await db.query(...);
  }
}

4. 实现任务停止逻辑

客户端触发tasks:stop时,取出对应控制器并触发终止:

socket.on('tasks:stop', ({ uid }) => {
  const controller = taskControllers.get(uid);
  if (controller) {
    controller.abort();
    console.log(`已发送终止信号给任务 ${uid}`);
  } else {
    console.log(`任务 ${uid} 不存在或已结束`);
  }
});

注意事项

  • 若Node.js版本低于15,可使用events模块自定义终止事件,或用第三方库p-cancelable替代AbortController。
  • 对于IO密集型操作(如数据库查询),优先选择支持AbortSignal的驱动版本,能更高效中断正在进行的IO请求;若驱动不支持,需在操作前后手动检查终止标志。
  • 任务无论正常结束还是被终止,都要从taskControllers中删除对应控制器,防止内存泄漏。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 23:43:33