Кладёте payload (или ID задачи) в ZSet со score = unix time выполнения; воркер периодически ZRANGEBYSCORE до now и забирает due jobs (ZREMRANGEBYSCORE/pop-паттерн).
Разбор
- Нужна атомарность забора — Lua или
ZPOPMIN где доступно.
- Храните в ZSet ID, а тело — в отдельном ключе, если payload большой.
- Следите за clock skew между нодами аппа.
- Альтернатива — Streams + отдельный scheduler.
Итог
ZSet+score-as-time — стандартный delayed/scheduled queue на Redis.