LLD Hub
llddistributed-systemscommand-patternobserver

How to Design a Distributed Job Scheduler | LLD Interview Guide

Design a job scheduling system with cron support, priority queues, retry with backoff, and distributed workers. Senior-level LLD problem at Amazon, Flipkart.

16 April 2025·10 min read

Practice this problem

Distributed Job Scheduler — get AI-scored feedback on your solution

Solve it →

A Distributed Job Scheduler is an advanced LLD problem that tests your understanding of priority queues, retry policies, distributed coordination, and the Command pattern. It's asked at Amazon, Flipkart, and companies with complex background processing needs.

Core Entities

  • Job — the unit of work; has type, payload, priority, schedule
  • JobDefinition — template for a job type (max retries, timeout)
  • Worker — picks up jobs and executes them
  • Queue — priority queue of pending jobs
  • Scheduler — triggers recurring/cron jobs
  • WorkerRegistry — tracks live workers via heartbeat

Command Pattern for Jobs

interface JobCommand { execute(payload: any): Promise<JobResult>; }

class SendEmailJob implements JobCommand {
  async execute(payload: { to: string; subject: string; body: string }) {
    await this.emailService.send(payload.to, payload.subject, payload.body);
    return JobResult.success();
  }
}

class GenerateReportJob implements JobCommand {
  async execute(payload: { reportType: string; userId: string }) {
    const report = await this.reportService.generate(payload.reportType, payload.userId);
    await this.storageService.upload(report);
    return JobResult.success();
  }
}

Priority Queue

enum JobPriority { HIGH = 1, MEDIUM = 2, LOW = 3 }

class JobQueue {
  private queue: Job[] = [];

  enqueue(job: Job) {
    this.queue.push(job);
    this.queue.sort((a, b) => {
      if (a.priority !== b.priority) return a.priority - b.priority;
      return a.scheduledAt.getTime() - b.scheduledAt.getTime(); // FIFO within priority
    });
  }

  dequeue(): Job | null { return this.queue.shift() ?? null; }
}

Retry with Exponential Backoff

class Worker {
  async execute(job: Job) {
    try {
      const command = this.commandRegistry.get(job.type);
      const result = await command.execute(job.payload);
      job.status = JobStatus.COMPLETED;
    } catch (error) {
      job.attempts++;
      if (job.attempts >= job.definition.maxRetries) {
        job.status = JobStatus.FAILED;
        this.dlq.add(job); // Dead letter queue
      } else {
        const delay = Math.pow(2, job.attempts) * 1000; // Exponential backoff
        job.scheduledAt = new Date(Date.now() + delay);
        job.status = JobStatus.PENDING;
        this.queue.enqueue(job);
      }
    }
  }
}

Cron Scheduling

class CronScheduler {
  schedule(jobType: string, cronExpression: string, payload: any) {
    const definition = new RecurringJobDefinition(jobType, cronExpression, payload);
    this.definitions.save(definition);
  }

  tick() { // Called every minute
    const due = this.definitions.filter(d => this.isDue(d.cronExpression));
    due.forEach(d => this.queue.enqueue(new Job(d)));
  }
}

Ready to practice?

Submit your solution and get AI-scored feedback on OOP, SOLID principles, design patterns, and code quality.

Solve Distributed Job Scheduler