AdonisJs中socket.io在adonis5-scheduler任务内调用emit失效
AdonisJs 集成socket.io在定时任务中失效修复
问题原因
出现「控制器中Ws.io.emit正常、定时任务中emit不生效但日志正常打印」的现象,核心是两个逻辑问题:
- Ws服务的初始化逻辑没有绑定到应用全局启动生命周期,仅在HTTP请求链路(控制器、路由处理逻辑)中被触发执行。定时任务独立于HTTP请求生命周期运行,任务触发时Ws.io实例要么未初始化,要么没有绑定到正在监听端口的AdonisServer实例上。
- 默认配置下adonis5-scheduler会在独立子进程中执行任务,子进程与主HTTP进程内存空间隔离,子进程中拿到的Ws实例和主进程对外提供服务的socket.io实例不是同一个,无法向已连接的客户端推送消息。
修复步骤
- 全局启动阶段初始化Ws服务
不要等HTTP请求触发才调用Ws.boot(),将初始化逻辑放到应用全局启动的ready钩子里,确保服务启动时Ws实例就完成挂载。
修改providers/AppProvider.ts文件,加入Ws初始化逻辑:
// 替换成你项目中Ws模块的实际引入路径 import Ws from 'App/Services/Ws' export default class AppProvider { public async ready() { Ws.boot() } }
- 关闭定时任务的子进程运行模式
在项目配置目录下新建/修改config/scheduler.ts,关闭worker进程模式,让定时任务和主HTTP服务运行在同一进程,共享内存中的Ws实例:
export default { runInWorker: false, path: 'app/Tasks' // 保持和你实际存放定时任务的目录路径一致 }
- 增加实例存在性校验
在定时任务的handle方法中增加兜底校验,避免极端场景下实例未初始化导致静默失败:
import { BaseTask } from 'adonis5-scheduler/build' // 替换成你项目中Ws模块的实际引入路径 import Ws from 'App/Services/Ws' export default class GetRouletteGame extends BaseTask { public static get schedule() { return '*/3 * * * * *' } public static get useLock() { return false } public async handle() { if (!Ws.io) { Ws.boot() } Ws.io.emit(`taskName`, 1) console.log('ok') } }
注意点
你当前的Ws模块实现不需要额外调用io.listen(),因为已经传入了已启动的AdonisServer实例,重复监听端口反而会导致端口占用报错。
内容的提问来源于stack exchange,提问作者marcelo.delta
相关产品推荐
相关产品推荐

