DevPrep
  • Interview Prep
  • Projects
  • Resources
  • Pricing
  • About Us
Submit Question
DevPrep
  • Pricing
  • About Us
Submit Question

Practice

  • JavaScript
  • DSA
  • Machine Coding
  • System Design

Resources

  • Learning Tracks
  • Articles
  • Roadmaps
  • Compare Concepts
  • Glossary
  • Developer Tools
  • All Questions

Company

  • About
  • Pricing

Legal

  • Privacy Policy
  • Terms of Service
DevPrep

© 2026 DevPrep. All rights reserved.

← Back to Questions
HardMachine Coding

Implement a Delayed Job Queue

557 views

Problem Statement

Implement a job queue where jobs can be scheduled to run after a delay. Pop() should block until a job is ready.

Requirements

  • Push(job, delay): Schedule a job to run after delay
  • Pop(): Block until the next job is ready, then return it
  • Jobs execute in scheduled order
  • Thread-safe

Implementation with Min-Heap

package delayqueue

import (
    "container/heap"
    "sync"
    "time"
)

type Job struct {
    ID       string
    Payload  interface{}
    RunAt    time.Time
    Priority int
}

type jobHeap []*Job

func (h jobHeap) Len() int           { return len(h) }
func (h jobHeap) Less(i, j int) bool { return h[i].RunAt.Before(h[j].RunAt) }
func (h jobHeap) Swap(i, j int)      { h[i], h[j] = h[j], h[i] }

func (h *jobHeap) Push(x interface{}) {
    *h = append(*h, x.(*Job))
}

func (h *jobHeap) Pop() interface{} {
    old := *h
    n := len(old)
    x := old[n-1]
    *h = old[0 : n-1]
    return x
}

type DelayQueue struct {
    mu      sync.Mutex
    cond    *sync.Cond
    jobs    jobHeap
    closed  bool
    timer   *time.Timer
}

func New() *DelayQueue {
    dq := &DelayQueue{
        jobs: make(jobHeap, 0),
    }
    dq.cond = sync.NewCond(&dq.mu)
    heap.Init(&dq.jobs)
    return dq
}

func (dq *DelayQueue) Push(id string, payload interface{}, delay time.Duration) {
    dq.mu.Lock()
    defer dq.mu.Unlock()
    
    job := &Job{
        ID:      id,
        Payload: payload,
        RunAt:   time.Now().Add(delay),
    }
    
    heap.Push(&dq.jobs, job)
    dq.cond.Signal() // Wake up waiting consumer
}

func (dq *DelayQueue) Pop() (*Job, bool) {
    dq.mu.Lock()
    defer dq.mu.Unlock()
    
    for {
        if dq.closed {
            return nil, false
        }
        
        if len(dq.jobs) == 0 {
            dq.cond.Wait()
            continue
        }
        
        next := dq.jobs[0]
        now := time.Now()
        
        if next.RunAt.After(now) {
            // Wait until job is ready
            waitTime := next.RunAt.Sub(now)
            
            // Use timer with condition variable
            go func() {
                time.Sleep(waitTime)
                dq.cond.Signal()
            }()
            
            dq.cond.Wait()
            continue
        }
        
        // Job is ready
        job := heap.Pop(&dq.jobs).(*Job)
        return job, true
    }
}

func (dq *DelayQueue) Close() {
    dq.mu.Lock()
    defer dq.mu.Unlock()
    dq.closed = true
    dq.cond.Broadcast()
}

func (dq *DelayQueue) Len() int {
    dq.mu.Lock()
    defer dq.mu.Unlock()
    return len(dq.jobs)
}

Usage

func main() {
    queue := delayqueue.New()
    
    // Push jobs with different delays
    queue.Push("job-1", "data-1", 5*time.Second)
    queue.Push("job-2", "data-2", 2*time.Second)
    queue.Push("job-3", "data-3", 10*time.Second)
    
    // Consumer
    go func() {
        for {
            job, ok := queue.Pop()
            if !ok {
                return
            }
            fmt.Printf("Processing %s at %v\n", job.ID, time.Now())
        }
    }()
    
    // Output (in order):
    // Processing job-2 at ... (after 2s)
    // Processing job-1 at ... (after 5s)
    // Processing job-3 at ... (after 10s)
}

Sample Test Cases

Case 1
Input
job={task: "email", delay: 5s}
Expected Output
Job executes after 5 second delay
Case 2
Input
jobs=[{delay:3s}, {delay:1s}, {delay:2s}]
Expected Output
Jobs execute in order: 1s, 2s, 3s
Case 3
Input
[
    {"id": "job-1", "payload": "data-1", "delay": 100},
    {"id": "job-2", "payload": "data-2", "delay": 50},
    {"id": "job-3", "payload": "data-3", "delay": 150}
]
Expected Output
[
    {"id": "job-2", "payload": "data-2"},
    {"id": "job-1", "payload": "data-1"},
    {"id": "job-3", "payload": "data-3"}
]
Case 4
Input
[
    {"id": "job-a", "payload": "payload-a", "delay": 200},
    {"id": "job-b", "payload": "payload-b", "delay": 200},
    {"id": "job-c", "payload": "payload-c", "delay": 200}
]
Expected Output
[
    {"id": "job-a", "payload": "payload-a"},
    {"id": "job-b", "payload": "payload-b"},
    {"id": "job-c", "payload": "payload-c"}
]
Case 5
Input
[
    {"id": "job-single", "payload": "single-item", "delay": 10}
]
Expected Output
[
    {"id": "job-single", "payload": "single-item"}
]

No solutions yet

Be the first to share a solution for this question.

Comments (0)

Sign in to leave a comment.

No comments yet. Be the first to comment.

Stats

Views
557
Likes
0
Solutions
0
Comments
0

Category

Backend Engineering

Languages

Go