작업을 만료 시각을 key로 하는 시간 버킷(time-bucketed) / 우선순위 큐에 저장하고, 지금 만료되는 작업만 poll하며, at-least-once 전달로 idempotent worker에게 넘기십시오. 매 tick마다 1천만 row를 절대 스캔하지 말고, 발화 시각(fire time)으로 인덱싱하여 각 poll이 만료된 것만 건드리도록 하십시오.
아키텍처
text
API ─▶ Task store (DB/Redis ZSET, score = due_ts) ── 10M tasks, sharded
│
Poller (leader per partition) ── ZPOPMIN due<=now ──▶ Ready queue (Kafka)
│ leader election (etcd/ZK) │
▼ ▼
other pollers idle/standby Worker pool (idempotent)
└─ ack ✔ / retry ✖ ─▶ DLQ
