出了问题看哪里
出问题时该看哪里,以及 gotick 在 Redis 里留下了什么。
检查界面
内置一个网页界面,能看到:哪些调用在跑、每一个停在哪一步、各步花了多久、错在哪里、还要睡多久。它就是一个普通的 http.Handler,直接读 Redis,不需要连上正在跑的 worker。它在独立子包里,不 import 它的人二进制一个字节都不会涨。它能看到你传进去的所有 metadata,所以前面务必加鉴权。
01挂到你的 mux 上
折进一个你已经在发布的服务里,鉴权中间件也直接复用现成的。工作量最小。
h, _ := ui.NewHandler(ui.Options{ RootPath: "/_gotick", Store: store.NewRedisStore(rdb), Auth: myAuthMiddleware,})mux.Handle("/_gotick/", h)02给它一个独立端口
适合本身没有 HTTP 服务的进程,用法类比 net/http/pprof。没给凭据就想绑非回环地址,会被直接拒绝,不是只警告一句。
go ui.ListenAndServe("127.0.0.1:6060", ui.Options{ Store: store.NewRedisStore(rdb),})03从终端看一眼
线上不对劲:不改代码、不发版,把命令行指向 Redis 就能看现场。
go run github.com/zbysir/gotick/cmd/gotick@latest ui \ -redis redis://localhost:6379/0命令行
gotick inspect 打印一次调用的所有步骤和 metadata:状态、重试次数、下次执行时刻、最后一次的错误。它同样只读 Redis,卡住的流程不必碰正在运行的服务就能诊断。想把界面当独立服务跑,也有现成的容器镜像。
$ gotick inspect -redis redis://localhost:6379/0 9f2ac41b8e7d callId 9f2ac41b8e7dtasks 3 TASK STATUS RETRY RUN AT LAST ERRORsend-email retry 1 2026-08-18T09:12:06Z smtp timeoutstart done 0 - -wait sleep 0 2026-08-18T09:12:03Z - metadata order_id = ORD-1存了什么,存多久
全都在你指给 gotick 的那个 Redis 里。清理是自动的,下面这些是默认值。
| 键 | 里面是什么 | 保留多久 |
|---|---|---|
| <callId>_status | 每个步骤一个字段:状态、重试次数、耗时、最后一次错误 | 调用进终态之后 7 天 |
| <callId>_meta | 你传的 metadata、Memo 的结果、已投递的信号 | 调用进终态之后 7 天 |
| gotick:run:<callId> | 界面列表里那条运行摘要 | 7 天 TTL |
| gotick:runs、gotick:flow:<id>:runs | 按开始时间索引运行记录的有序集合 | 超过保留期的会被裁掉,最多每 10 分钟裁一次 |
| gotick:flows | 跑过的 flow id 列表 | 不清理,大小取决于你有多少 flow |
| gotick:keys:<flowId> | 业务 key 到 callId 的映射,每个 flow 一张哈希表 | 对应的调用一结束就删掉那一条 |
| asynq:* | asynq 自己的队列和统计 | 成功的任务不保留;重试耗尽的归档 90 天 |
配置项
| 字段 | 作用 |
|---|---|
| RedisURL / RedisClient | Redis 在哪。传自己的 client 可以复用已有的连接池。 |
| Queue | 队列命名空间,默认 gotick。要把一组流程和另一组隔开就改这里。 |
| Concurrency | 一个 worker 同时执行多少个任务,默认 10。 |
| DelayedTaskCheckInterval | 已排期的任务多久被搬到待执行,也就是每个 Sleep、每次重试退避的实际精度,默认 500 毫秒。调大省 Redis 轮询,代价是醒得没那么准。 |
| TaskCheckInterval | 队列空的时候多久查一次新任务,默认 100 毫秒。 |
| ConsumeLegacyPerFlowQueues | 从旧的「一个 flow 一个队列」升级时打开,让 worker 额外消费旧队列,排空之后再关掉。 |