Katkat

Design a Distributed Job Scheduler with Run Logs and Exactly-Once Execution

AmazonSoftware Engineer · Onsite

Last updated

Design a highly available distributed job scheduler that handles one-time and recurring jobs, collects execution logs, and rigorously addresses the practical boundaries of exactly-once execution.

Scenario

You are asked to design a scalable distributed job scheduler for a multi-tenant cloud platform (similar to AWS EventBridge combined with AWS Batch). The platform allows users to schedule arbitrary compute tasks, monitors their execution across a dynamic pool of worker machines, and stores detailed execution logs for auditing and debugging.

A critical requirement emphasized by stakeholders is handling failure modes gracefully: workers may crash mid-task, network partitions will occur, and duplicate executions must be strictly controlled or prevented.

Requirements

Functional Requirements

  • Job Definition & Scheduling: Support one-off jobs (execute at timestamp T) and recurring jobs (cron-based schedules).
  • Job Execution: Assign jobs to a pool of distributed workers based on priority and availability.
  • Status & Run Logs: Capture real-time status transitions (e.g., SCHEDULED, RUNNING, COMPLETED, FAILED) and ingest/store output logs (stdout/stderr) for each execution run.
  • Cancellation & Retries: Allow users to abort scheduled or running jobs, and configure retry policies with exponential backoff on failure.
  • Delivery & Execution Guarantees: Address the client expectation of "exactly-once execution" and design mechanisms (e.g., distributed leases, fencing tokens, idempotency) to handle duplicates and split-brain scenarios.

Non-Functional Requirements

  • Scalability: Support 100 million registered job definitions, triggering up to 100,000 executions per minute at peak (~2,000 executions/second).
  • Dispatch Latency: Jobs should begin executing within 5 seconds of their scheduled time.
  • Log Retention & Durability: Run logs must be durable and retrievable for at least 30 days.
  • Fault Tolerance: No single point of failure; scheduler nodes or workers crashing must not result in permanently orphaned or duplicate-executed jobs.

What Your Design Should Cover

  1. Core Architecture & Component Flow: Scheduler coordinator, time-bucketed delay queues, worker pools, and heartbeat managers.
  2. Data Model & State Management: Schema for job metadata, execution runs, and schedule triggers.
  3. Exactly-Once vs. At-Least-Once Analysis: Realistic trade-offs regarding distributed consensus, fencing tokens, and idempotent execution keys.
  4. Log Ingestion Pipeline: Architecture for handling bursty log streams from workers without impacting scheduling latency.
  5. Edge Cases: Handling worker network isolation, clock skew across nodes, and worker crash during log flushing.

Hints

Hint 1

Differentiate between 'exactly-once delivery' across the network (theoretically impossible under arbitrary partitions) and 'effectively-once execution' achieved via monotonically increasing fencing tokens and worker-side idempotency.

Hint 2

Partition scheduled jobs using time buckets (e.g., minute-level buckets) in a persistent key-value or document store to avoid full-table scans when polling for runnable tasks.

Hint 3

Decouple the log streaming pipeline from the scheduler control plane using an append-only distributed log (e.g., Kafka) or direct-to-object-storage chunked uploads to prevent log ingestion from starving task dispatching.

Follow-up questions

  • How does your design address clock skew across scheduler instances when evaluating cron expressions and triggering jobs?
  • If a worker loses its lease due to a temporary network partition but continues running the task locally, how do you prevent it from corrupting downstream state when a replacement worker is spawned?
  • How would you scale log search if users need to perform full-text or regex queries across petabytes of historical execution logs?