延迟 30 分钟的任务写了 zadd,两个小时后仍在 zset 里,ZRANGEBYSCORE 用当前时间取不到任何成员。zset 里的 score 是 1763 开头的十位数。碰到这种情况,我一般先确认改动有没有真的生效。
原因不复杂,入队时用的是秒级时间戳,扫描端拿的是毫秒,量级差 1000 倍,判断条件永远不成立。两边还各写了一份当前时间,时区不同时偏差会更大。
「延迟任务未触发」相关的验证我通常做两遍,改完一次、隔天再看一次,确认不是临时生效。报错里带路径的,先去看那个路径在不在、权限对不对。
ZADD delay:job 1763000000000 '{"id":1}'
ZRANGEBYSCORE delay:job 0 1763000900000 LIMIT 0 10
ZREM delay:job '{"id":1}'
同一份配置存在多处的,先确认改的是被加载的那一份。新版本先放一台机器上跑一天再全量,问题一般在这段时间暴露。
具体做法是,统一时间单位 入队和扫描都用毫秒 并在代码里写死乘以 1000;扫描用 ZRANGEBYSCORE key 0 now LIMIT 0 100 一次取一批;取到之后先 ZREM 再投递 避免多实例重复取;加监控统计 zset 最小 score 与当前时间的差值。
最后用这个标准收尾,投一个延迟 1 分钟的任务 60 秒后能被取到并执行 zset 里不再残留该成员。
