Build a Priority Task Queue

Difficulty: Medium · Category: Task Scheduler · Languages: Java 17, Python 3.11, Go 1.22, Node.js 20, TypeScript 5.x

Priority Task Queue

Background

Task queues are fundamental building blocks of distributed systems. They decouple producers from consumers, smooth out traffic spikes, and enable reliable background processing. A priority-based task queue ensures that the most important work is processed first — critical for systems where not all tasks are equal (e.g., payment processing before analytics).

Adding retry semantics and a dead-letter queue makes the system resilient: transient failures are automatically retried, and permanently failing tasks are quarantined for manual investigation instead of being lost or retried forever.

Your Task

Implement the TaskQueueContract interface. Your implementation must:

  1. Persist all state — queue entries and task metadata must survive restarts.
  2. Dequeue tasks in descending priority order (highest first).
  3. Be thread-safe: concurrent dequeue calls must never return the same task to two consumers.
  4. Track the full task lifecycle: PENDING → PROCESSING → COMPLETED, or PENDING → PROCESSING → FAILED → (retry) → PENDING → ...
  5. Move tasks that exceed the configured max retries to a dead-letter queue.

Recommended infrastructure: redis — fast key-value store with atomic operations ideal for queue semantics.

How It Works

The platform injects your chosen infrastructure SDK(s) via constructor. For example, if you select Redis:

public class MyTaskQueue implements TaskQueueContract {
    private final RedisClient redis;

    public MyTaskQueue(RedisClient redis) {
        this.redis = redis;
    }

    // ... implement methods using redis.zadd(), redis.get(), etc.
}

See the SDK Docs tab for the full API reference of your chosen system.

Interface

public interface TaskQueueContract {
    String enqueue(String queueName, String payload, int priority);
    String dequeue(String queueName);
    String getPayload(String taskId);
    boolean acknowledge(String taskId);
    boolean fail(String taskId, String errorMessage);
    boolean retry(String taskId);
    String getStatus(String taskId);
    List<String> getDeadLetterQueue(String queueName);
    int getQueueSize(String queueName);
    void configureMaxRetries(String queueName, int maxRetries);
}

Method Details

MethodDescription
enqueueAdds a task with a payload and priority. Returns a unique task ID.
dequeueAtomically removes and returns the highest-priority task. Status → PROCESSING. Returns null if empty.
getPayloadReturns the original payload for a task ID.
acknowledgeMarks a PROCESSING task as COMPLETED.
failMarks a PROCESSING task as FAILED with an error message.
retryRe-enqueues a FAILED task. If max retries exceeded, moves to DLQ.
getStatusReturns PENDING, PROCESSING, COMPLETED, FAILED, or DEAD_LETTER.
getDeadLetterQueueLists task IDs in the DLQ for a queue.
getQueueSizeReturns the number of PENDING tasks.
configureMaxRetriesSets the max retry count for a queue (default 3).

Constraints

Examples

configureMaxRetries("jobs", 2)

t1 = enqueue("jobs", "send-email", 1)
t2 = enqueue("jobs", "process-payment", 10)
t3 = enqueue("jobs", "resize-image", 5)

dequeue("jobs")  → t2   (priority 10)
dequeue("jobs")  → t3   (priority 5)
dequeue("jobs")  → t1   (priority 1)
dequeue("jobs")  → null (empty)

acknowledge(t2)          → true   // COMPLETED
fail(t3, "timeout")      → true   // FAILED
retry(t3)                → true   // back to PENDING (retry 1/2)
// fail + retry again    → retry 2/2
// fail + retry again    → moved to DLQ

getDeadLetterQueue("jobs") → [t3]

Hints

Infrastructure your code runs against

How your solution is graded

Your score combines functional correctness (45%), performance (35%) and code quality (20%).

Practice this problem

Related LLD problems