Chaturmind
LearnDSASystem DesignDevOpsEngineering GrowthBlog
Start learning
Chaturmind

Structured learning paths for engineers who want to go deep. Written by practitioners.

Learn

  • Java
  • DSA
  • System Design
  • Spring Boot
  • AI / ML
  • DevOps
  • Engineering Growth

Company

  • Blog
  • Contact

Legal

  • Privacy Policy
  • Terms of Service

© 2026 Chaturmind. All rights reserved.

Built for engineers who want to go deep.


← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
Chaturmind
← Low-Level Design & Design Patterns

OOP Fundamentals & SOLID Principles

  • Object-Oriented Design Refresher
  • Single Responsibility & Open/Closed
  • Liskov Substitution & Interface Segregation
  • Dependency Inversion

Creational Design Patterns

  • Singleton Pattern
  • Factory & Abstract Factory
  • Builder Pattern
  • Prototype Pattern

Structural Design Patterns

  • Adapter & Facade
  • Decorator Pattern
  • Composite & Proxy
  • Bridge & Flyweight

Behavioral Design Patterns

  • Strategy Pattern
  • Observer Pattern
  • Command Pattern
  • Template Method
  • State Pattern
  • Chain of Responsibility
  • Iterator & Mediator
  • Visitor Pattern

Machine Coding Exercises

  • Parking Lot — Requirements & Class Design
  • Parking Lot — Implementation
  • Elevator System — Requirements & Class Design
  • Elevator System — Implementation & Scheduling
  • Library Management System
  • Tic-Tac-Toe / Board Game Design
  • Chess Engine Design
  • Vending Machine Design
  • ATM System Design
  • In-Memory Rate Limiter
  • Thread-Safe LRU Cache
  • Connection Pool Design
  • Producer-Consumer Class Design
  • Movie Ticket Booking System
  • Hotel Reservation System
  • Airline Booking / Seat Selection System
  • Splitwise / Expense Sharing System
  • Design a Logging Framework
  • Design a Notification/Observer-Based Pub-Sub
  • Design a Cache with Pluggable Eviction Policy
  • Design Snake and Ladder
  • Design a Card Game Framework
  • Design an Inventory Management System
  • Restaurant Management System
  • Food Delivery Order Matching
  • Design a Shopping Cart & Checkout Flow
  • Design a Recommendation Engine
  • Design a Job Scheduler
  • Design a Circuit Breaker
  • Design a Distributed ID Generator
  • Design a Pub-Sub Message Broker
  • Design Twitter/X
  • Multi-Pattern Problem: Design a Ride Booking Class Model
  • Multi-Pattern Problem: Design a Food Ordering Class Model
  • Design an Authentication/Authorization Module
  • Design a Form/Survey Builder
  • Design a Meeting Room / Calendar Booking System
  • Design a Search/Filter Engine for an E-Commerce Catalog
  • Design a Voting/Polling System
  • Design a Retry Mechanism with Backoff
  • Design a Health Check Aggregator
  • Design a Feature Flag System
  • Design a Config Management Client
  • Design a Leader Election Algorithm
  • Design a Distributed Counter
  • Design a Bloom Filter
  • Design a Consistent Hashing Ring
  • Design a Distributed Tracing Library
  • Design a Metrics Collection Library
  • Design an Audit Logging Framework
  • Design a Plugin/Extension System
  • Design a Workflow Engine
  • Multi-Pattern Capstone: Design a Food Delivery App
HomeLearnSystem DesignLow-Level Design & Design PatternsMachine Coding Exercises
✓ FreeIntermediate· 6 min read

Design a Job Scheduler

Job/Schedule/JobExecutor/JobQueue classes, a single-node priority-queue-by-next-run-time implementation, and the extension path toward a distributed scheduler.

Published September 23, 2026


Design a Job Scheduler

Core classes

interface Job { void execute(); }

class Schedule {
    Instant nextRunTime;
    Duration recurrenceInterval; // null for a one-time job
}

class ScheduledJob {
    Job job;
    Schedule schedule;
    String id;
}

Single-node implementation: priority queue ordered by next-run-time

class JobQueue {
    private final PriorityQueue<ScheduledJob> queue = new PriorityQueue<>(
        Comparator.comparing(sj -> sj.schedule.nextRunTime) // always exposes the SOONEST job at the top
    );

    synchronized void schedule(ScheduledJob job) { queue.offer(job); }
    synchronized ScheduledJob peekNext() { return queue.peek(); }
    synchronized ScheduledJob pollNext() { return queue.poll(); }
}

class JobExecutor {
    private final JobQueue jobQueue;
    private volatile boolean running = true;

    void run() {
        while (running) {
            ScheduledJob next = jobQueue.peekNext();
            if (next == null) { sleepBriefly(); continue; }

            long waitMs = Duration.between(Instant.now(), next.schedule.nextRunTime).toMillis();
            if (waitMs > 0) { sleepFor(waitMs); continue; } // not due yet — wait and re-check

            jobQueue.pollNext().job.execute();
            if (next.schedule.recurrenceInterval != null) {
                next.schedule.nextRunTime = Instant.now().plus(next.schedule.recurrenceInterval);
                jobQueue.schedule(next); // re-insert — the priority queue naturally re-sorts it to its new position
            }
        }
    }
}

A priority queue ordered by nextRunTime means "what's the next job to run" is always an O(log n) peek/poll away, regardless of how many jobs are scheduled — no need to scan the full job list on every tick. Recurring jobs re-insert themselves with an updated nextRunTime after each execution, and the priority queue automatically places them correctly relative to every other pending job — no manual re-sorting logic needed.

Extending toward the distributed scheduler

This single-node design has an implicit, easy-to-miss assumption: exactly one JobExecutor process exists. Design: Distributed Task Scheduler's actual hard problems — finding "jobs due now" efficiently across a much larger job set (a time-bucketed structure instead of one in-memory priority queue), distributing execution across multiple worker nodes, and specifically avoiding double-execution of the same job when multiple workers could pick it up — are the direct extension points from this LLD foundation. The core data model (Job, Schedule, next-run-time ordering) transfers directly; what changes at distributed scale is where that priority ordering lives (a shared, coordinated store instead of one process's in-memory heap) and how workers coordinate to ensure only one of them actually claims and runs a given due job.

Follow-up questions this topic invites — and their answers

Q: Why does peekNext() exist as a separate method rather than always calling pollNext() and re-inserting if not yet due? A: Peeking avoids unnecessary remove-then-reinsert churn on the priority queue for a job that isn't due yet — pollNext() should only be called once a job is actually confirmed ready to execute, keeping the queue's O(log n) operations reserved for genuine state changes rather than repeated no-op poll/re-insert cycles on every check.

Q: What happens if execute() throws an exception for a recurring job — does it still get rescheduled? A: Worth deciding explicitly and stating the choice: rescheduling regardless of failure keeps the job running on its normal cadence despite one bad execution (appropriate for most cases), while NOT rescheduling on failure requires manual intervention to resume — the code above reschedules unconditionally, which is a specific, statable design decision, not an oversight.

Q: How would you avoid double-execution even on a SINGLE node with multiple executor threads? A: The synchronized JobQueue methods already prevent two threads from both polling the same ScheduledJob instance — pollNext() atomically removes it from the queue, so a second thread's pollNext() call simply won't see it, which is the single-node analog of the distributed double-execution problem, solved here by ordinary mutual exclusion rather than a distributed lock.

Q: Could missed jobs (the process was down when a job was due) be handled by this design? A: Not by the structure shown — a job whose nextRunTime already passed while the process was down would need explicit 'catch-up' handling (run immediately on restart, or skip to the next scheduled occurrence) rather than assuming JobExecutor.run() is always live at the exact moment a job comes due, which is a real gap worth naming when discussing production readiness.

Previous

Design a Recommendation Engine

Next

Design a Circuit Breaker

AI Tutor

Lesson: Design a Job Scheduler

Quick actions

AI responses can be inaccurate. Verify critical information.