Design Job Scheduler - Follow-up questions - Intuition First, Need more How
Here is solutions for Design Job Scheduler - Follow-up questions.
Main topic:
-
Job/Coordinate Service: assign worker for the job + Planner Service if needed.
-
Watcher Service (Cronjob): push ready job to queue.
-
Executor Service (Worker): consume signal from queue to do a job.
-
Bucket sharding for job_id
-
Windowing: watcher query [Now, Now + T]
-
Checkpoint: recurence to continue the job.
-
Idempotency: outbox table by job_id or task_id.
-
State Machine: for job running.

1. Patterns for Design Job Scheduler
-
Split to 3 services: Coordinator, Watcher, Worker
-
Deduplicate job_id: kafka partition, database lock (status), distributed lock.
-
Job with N tasks: assign tasks per worker.
-
Checkpoint: how to check point of a task -> Recurring Job Handling
-
Handling time-zone: for the scheduler.
-
Alert jobs: wait too long to execute.
-
Windowing and Batching: Each watcher only queries its shards for due_at in [now, now+W], e.g., 1–2 minutes, sliding every few seconds.
-
Bucket Sharding: key (hourlyBucket, shardId) with attributes ownerId, leaseExpiry -> only query by hour is enough.
-
Scheduler-side idempotency: outbox table
-
Workder-side idempotency: If Execution status == ENQUEUED, update to RUNNING, set workerId, startedAt, attempt++ -> If the conditional fails (already RUNNING/DONE), drop the message.
-
Dynamic sweeper: for job in status SCHEDULING or ENQUEUED for too long
-
Job lag and alerts: count of due_at <= now but status < ENQUEUED per shard.
-
Time-zone in scheduler service: must be right with timestamp.
-
Planner Service: reads job definitions and pre-generates concrete future execution records for some time horizon, like the next 24 hours.