Храните задачи в очереди с временными бакетами / приоритетной очереди по времени срабатывания, опрашивайте только задачи, срок которых наступил сейчас, и передавайте их идемпотентным воркерам с доставкой at-least-once. Никогда не сканируйте 10 млн строк на каждый тик — индексируйте по времени срабатывания, чтобы каждый опрос касался только того, что подошло по сроку.
Архитектура
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
