定时任务还想上 Hangfire?这个被 AI Agent 项目看上的 TickerQ,把反射全干掉了 - 张善友

定时任务还想上 Hangfire?这个被 AI Agent 项目看上的 TickerQ,把反射全干掉了 - 张善友

💡 原文中文,约6200字,阅读约需15分钟。
📝

内容提要

TickerQ 是 .NET 定时调度库,通过 Source Generator 在编译期注册作业,实现零反射并支持 Native AOT,自带持久化和免费 Dashboard。文章以 OpenClaw.NET 的 /loop 命令为例,展示用每分钟心跳加内存注册表实现动态调度,并注入系统消息驱动 AI Agent 定时巡检。作者认为它适合 AOT 项目和 AI Agent 场景,但尚年轻,简单任务不必引入。

🔎

延伸解读

编译期注册如何解决反射痛点

传统调度框架依赖反射扫描程序集来发现作业,导致启动慢、运行时开销大,且方法名和 cron 表达式以字符串形式存在,错误只能在运行时暴露。TickerQ 通过 Source Generator 在编译期完成作业注册,消除了反射扫描,使 cron 错误在编译期即报错,并支持 Native AOT 裁剪。对于追求快速启动和 AOT 部署的项目,这一设计是硬性优势。

动态调度的务实变通方案

TickerQ 当前版本仅支持编译期声明 cron 表达式,无法在运行时动态创建定时任务。OpenClaw.NET 的 /loop 命令通过一个每分钟触发的编译期心跳,配合内存中的 ConcurrentDictionary 注册表,实现了动态间隔的循环调度。这种方案未修改框架,也未引入额外调度依赖,以分钟级精度满足了 AI Agent 定时巡检的需求,为类似场景提供了可复用的思路。

AI Agent 定时循环的工程要点

OpenClaw.NET 的 /loop 实现展示了几个关键设计:通过消息管道注入系统消息,避免侵入 AgentRuntime;采用双层终止机制,主路径由模型调用工具显式声明完成,备用路径检测响应文本中的终止关键词,防止无限空转;整个实现零反射,依赖源生成和 FrozenSet,确保可编译进 AOT 二进制。这些做法对构建可靠的 Agent 循环有参考价值。

适用边界与当前局限

TickerQ 适合被 Hangfire 配置或收费困扰、需要 Native AOT、免费监控面板或多节点协调的项目,以及为 AI Agent 添加定时心跳的场景。但它仍较年轻,生产验证不如老牌框架,文档尚在完善,且 /loop 的动态调度依赖内存注册表,进程重启后活跃循环会丢失。简单任务使用 PeriodicTimer 即可,不必引入框架。

Q&A

TickerQ 和 Hangfire 在作业注册方式上有什么本质区别?

TickerQ 通过 Source Generator 在编译期注册作业,实现零反射;而 Hangfire 基于反射在运行时扫描程序集发现作业。

TickerQ 如何实现动态调度?

TickerQ 本身只支持编译期声明 cron 表达式,但可以通过一个每分钟 tick 一次的 TickerQ 定时器作为心跳,配合运行时维护的 ConcurrentDictionary 内存注册表,扫描到期任务来实现动态调度。

TickerQ 支持 Native AOT 吗?

支持。TickerQ 通过 Source Generator 在编译期生成所有作业注册代码,运行时零反射,因此可裁剪、可 AOT,官方明确标注 Native AOT ready。

TickerQ 的 Dashboard 收费吗?

不收费。TickerQ 自带基于 SignalR 的实时监控面板,可以查看执行状态、失败记录、重试情况,还能直接在面板上启用或禁用 cron 作业,无需改代码或重新发布。

OpenClaw.NET 为什么选择 TickerQ 作为定时调度库?

因为 OpenClaw.NET 以 Native AOT 优先,需要零反射、可裁剪的调度库。TickerQ 的源生成和零反射特性使其能编进 AOT 二进制,cron 编译期校验,核心包零外部依赖,符合其技术选型要求。

TickerQ 目前有哪些不足?

TickerQ 还比较年轻,生产验证不如 Hangfire;文档还在追赶代码;动态调度依赖内存注册表,进程重启后活跃任务会丢失;简单场景引入框架可能过度。

🏷️

标签

➡️

继续阅读