Bird
Raised Fist0

Job Scheduler

LLDmediumInterview freq: medium
Choose your preparation mode4 modes available
🏗️
Job Scheduler
Design a Job Scheduler with Job, Cron Expression, Priority Queue, and Retry Policy using Java OOP principles
mediumInfrastructure and Utility SystemsFreq: medium
Prerequisites:OOP FundamentalsJava Concurrency BasicsDesign Patterns (Strategy, Template Method, Singleton)Data Structures (Priority Queue)
⚙️
Functional Requirements
  • Support cron expression parsing and next execution time calculation
  • Maintain a priority queue of jobs to execute next
  • Support configurable retry policies per job
  • Ensure thread-safe scheduling and execution of jobs
  • Allow job cancellation and rescheduling
  • Persist job metadata and execution history (out of scope for this version)
  • Provide hooks for job success and failure callbacks
👤
Use Cases
  • Schedule a job with a cron expression and priority
  • Execute jobs according to schedule and priority
  • Retry failed jobs based on retry policy
  • Cancel or reschedule existing jobs
  • Query job status and history
  • Handle concurrent job executions safely
🧑‍💻
Actors
  • System Administrator
  • Scheduler Engine
  • Job Executor
  • Monitoring Service
❓
Clarifying Questions to Ask
  • How many concurrent threads will execute jobs? (Assume configurable thread pool size)
  • Should the scheduler support dynamic priority changes at runtime?
  • What is the expected maximum number of scheduled jobs?
  • How should the system behave if a job execution exceeds its scheduled interval?
  • Is there a pricing or cost model affecting job scheduling priority?
  • Are there any constraints on retry intervals or maximum retry attempts?
  • Should the scheduler support immediate job execution outside cron schedule?
Out of Scope
✗ Distributed scheduling across multiple nodes
✗ Persistent storage and recovery
✗ Complex job dependency graphs
✗ User authentication and authorization
🔢
Enumerations
enum JobStatus
PENDING | RUNNING | SUCCESS | FAILED | CANCELLED
Defines all possible states of a job lifecycle to prevent invalid states and enable exhaustive switch-case handling.
enum RetryPolicyType
FIXED_DELAY | EXPONENTIAL_BACKOFF | NONE
Encapsulates retry strategies to enforce type safety and allow strategy pattern implementation.
enum Priority
LOW | MEDIUM | HIGH | CRITICAL
Defines job priority levels to enable priority queue ordering and prevent magic numbers.
📦
Job
7 fields
private final String jobIdprivate final Runnable taskprivate final CronExpression cronExpressionprivate volatile JobStatus statusprivate final Priority priorityprivate final RetryPolicy retryPolicyprivate volatile int retryCount
Represents a schedulable unit of work with scheduling metadata, execution status, and retry logic.
public synchronized LocalDateTime getNextExecutionTime()Calculates the next execution time based on the cron expression.
public synchronized void execute() throws ExceptionExecutes the job's task and updates status atomically.
public synchronized void incrementRetryCount()Atomically increments the retry count.
public synchronized void resetRetryCount()Resets retry count to zero.
public synchronized void cancel()Cancels the job and updates status.
📦
CronExpression
2 fields
private final String expressionprivate final CronParser parser
Parses and validates cron expressions and calculates next valid execution times.
public LocalDateTime getNextValidTimeAfter(LocalDateTime afterTime)Returns the next valid execution time after the given timestamp.
public boolean isValid()Validates the cron expression syntax.
📦
RetryPolicy
3 fields
private final RetryPolicyType typeprivate final int maxRetriesprivate final long delayMillis
Defines retry behavior for failed jobs including max retries and delay strategy.
public boolean shouldRetry(int currentRetryCount)Determines if the job should be retried based on current retry count.
public long getNextDelay(int currentRetryCount)Calculates delay before next retry based on policy type.
📦
JobScheduler
4 fields
private final PriorityBlockingQueue<Job> jobQueueprivate final ExecutorService executorServiceprivate final ConcurrentHashMap<String, Job> jobsMapprivate final Object lock = new Object()
Manages job scheduling, execution, retry, and cancellation with thread-safe operations.
public synchronized boolean scheduleJob(Job job)Adds a job to the priority queue and jobs map atomically.
public synchronized boolean cancelJob(String jobId)Cancels a scheduled job if present.
public void runSchedulerLoop()Continuously polls the queue and submits jobs for execution respecting schedule and priority.
public synchronized void retryJob(Job job)Handles retry logic for failed jobs according to retry policy.
📦
JobExecutor
1 fields
private final ExecutorService executorService
Executes jobs asynchronously and reports success or failure back to scheduler.
public Future<?> submitJob(Job job)Submits a job for asynchronous execution.
🔗
Relationships
JobScheduler◆──►Job[1..*]
compositionJobScheduler owns Job lifecycle; jobs cannot exist independently
Job◇──►CronExpression[1]
aggregationCronExpression can exist independently; Job references it
Job◇──►RetryPolicy[1]
aggregationRetryPolicy can exist independently; Job references it
JobScheduler──►JobExecutor[1]
associationJobExecutor exists independently; JobScheduler uses it

Practice

(1/5)
1. In designing the ESPNcricinfo system, should the Ball entity be modeled as an abstract class or an interface? Consider that Ball has state like ballNumber and behavior like calculateRuns(). Which is the best choice and why?
easy
A. Abstract class, because Ball has shared state and behavior that subclasses inherit.
B. Interface, because Ball only defines behavior and no state should be stored.
C. Interface, because Java interfaces can now have default methods with state variables.
D. Abstract class, because it allows multiple inheritance of Ball features.

Solution

  1. Step 1: Analyze Ball's state and behavior

    Ball has state (ballNumber) and behavior (calculateRuns), so it needs to store data and provide common logic.
  2. Step 2: Abstract class vs interface for state

    Interfaces cannot hold instance state; abstract classes can hold state and provide shared implementation.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Stateful entity with behavior -> abstract class [check]
Hint: Stateful with behavior -> abstract class, stateless behavior -> interface [check]
Common Mistakes:
2. In the LinkedIn OOP design, the ConnectionManager class uses a private constructor and a static synchronized getInstance() method to provide a single instance. Which design pattern is applied here, and why is this the correct choice for managing user connections?
easy
A. Factory pattern, because it creates different types of connections dynamically.
B. Singleton pattern, to ensure only one instance manages all user connections globally.
C. Builder pattern, to incrementally construct complex connection objects.
D. Prototype pattern, to clone existing connection instances for performance.

Solution

  1. Step 1: Identify the pattern from constructor and method signature

    The private constructor and static synchronized getInstance() method are classic signs of the Singleton pattern, ensuring a single instance.
  2. Step 2: Reason why Singleton fits connection management

    Managing user connections globally requires a single shared instance to avoid inconsistent states or duplicated connection managers.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Singleton ensures one global ConnectionManager instance [check]
Hint: Private constructor + static getInstance() -> Singleton [check]
Common Mistakes:
3. In the messaging system, the DeliveryStatus class has a method markDelivered() that updates the delivery state. Without synchronizing this method, which exact thread interleaving causes inconsistent delivery status updates?
medium
A. Thread 1 reads status as undelivered, context switch; Thread 2 reads undelivered, both set delivered, overwriting each other's update.
B. Thread 1 calls markDelivered() while Thread 2 calls markFailed(), causing deadlock.
C. Thread 1 updates status to delivered, but Thread 2 never sees the update due to caching.
D. Thread 1 and Thread 2 both call markDelivered() simultaneously, causing a crash.

Solution

  1. Step 1: Identify the race condition in markDelivered()

    Without synchronization, two threads can read the undelivered status before either writes the delivered status.
  2. Step 2: Trace the interleaving causing lost update

    Thread 1 reads undelivered -> context switch -> Thread 2 reads undelivered -> both write delivered, one overwriting the other's update.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Check-then-act without sync -> lost update race condition [check]
Hint: Check-then-act gap -> lost update race [check]
Common Mistakes:
4. The system must support ElectricCar vehicles needing ChargingSpot parking. What is the minimum change to the current design to support this without modifying existing classes?
hard
A. Add a boolean isElectric flag to Vehicle and ParkingSpot classes and update all compatibility checks.
B. Modify existing Vehicle and ParkingSpot classes to add electric-specific fields and logic.
C. Create a new ElectricVehicleManager class that handles electric cars separately, duplicating some logic.
D. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map externally.

Solution

  1. Step 1: Identify extensibility without modifying existing classes

    Adding new enum values and subclassing allows extension without changing existing class code, respecting OCP.
  2. Step 2: Update compatibility externally

    Updating SpotCompatibility map outside existing classes avoids modifying their code, enabling new vehicle-spot matching.
  3. Final Answer:

    Option D -> Option D
  4. Quick Check:

    Extend enums + subclass + external map update -> no existing class changes [check]
Hint: Extend enums + subclass + external map -> no existing class changes [check]
Common Mistakes:
5. To support ElectricCar orders requiring ChargingSpots in the existing Order Management System, what is the minimum change that respects extensibility without modifying existing classes?
hard
A. Modify VehicleType enum to include ElectricCar and add charging logic inside existing Vehicle class.
B. Create a new ElectricCar class and modify Order class to handle charging spots explicitly.
C. Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map externally.
D. Add charging spot logic inside existing Spot class and modify OrderState to handle ElectricCar states.

Solution

  1. Step 1: Identify extensibility requirements

    New vehicle and spot types must be added without modifying existing classes to respect OCP.
  2. Step 2: Evaluate options

    Add ELECTRIC_CAR to VehicleType enum, CHARGING to SpotType enum, create ElectricCar subclass, and update SpotCompatibility map externally. adds new enum values and classes externally, updating compatibility map without changing existing code; Options B, C, D modify existing classes violating OCP.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Adding new enums and classes externally respects OCP [check]
Hint: Add new enums and classes externally, no existing class changes [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard