TypeDrop
2026-05-13 Challenge
2026-05-13
Hard
Typed Async Job Scheduler with Priority Queues
You're building the task-execution layer for a distributed background-job platform. Raw job definitions arrive as `unknown` from multiple producer services; your scheduler must validate them, enqueue them into typed priority queues, execute batches with a concurrency limit and per-job timeout, and return a strongly-typed execution report — with zero `any`.
Goals
- Implement `validateJob` to parse `unknown` payloads into a branded `Job`, collecting ALL validation errors before returning.
- Implement `buildPriorityQueue` to perform a stable sort of jobs by their priority weight.
- Implement `executeJob` to run a job with `Promise.race`-based timeout and per-failure retry logic, returning a discriminated `JobOutcome`.
- Implement `runScheduler` to validate raw inputs, group and sort jobs into per-queue priority queues, and execute them under a global concurrency limit, returning a fully-typed `SchedulerReport`.
challenge.ts
type JobPriority = "critical" | "high" | "normal" | "low";
type JobId = string & { readonly __brand: "JobId" };
type QueueId = string & { readonly __brand: "QueueId" };
interface Job {
readonly id: JobId;
readonly queueId: QueueId;
readonly priority: JobPriority;
readonly timeoutMs: number; // 100 – 30_000
readonly payload: Record<string, unknown>;
readonly maxRetries: number; // 0 – 5
}
type JobOutcome =
| { readonly status: "succeeded"; readonly jobId: JobId; readonly durationMs: number }
| { readonly status: "failed"; readonly jobId: JobId; readonly error: string; readonly attempts: number }
| { readonly status: "timed_out"; readonly jobId: JobId; readonly timeoutMs: number };
type Result<T, E> =
| { readonly ok: true; readonly value: T }
| { readonly ok: false; readonly error: E };
// --- Four functions to implement ---
function validateJob(raw: unknown): Result<Job, ValidationError[]>;
function buildPriorityQueue(jobs: readonly Job[]): readonly Job[];
async function executeJob(job: Job, handler: JobHandler): Promise<JobOutcome>;
async function runScheduler(
rawJobs: readonly unknown[],
handler: JobHandler,
config: SchedulerConfig
): Promise<SchedulerReport>;
Hints (click to reveal)
Hints
- For the concurrency limiter in `runScheduler`, maintain a counter of active slots and use a queue of pending resolvers — or track in-flight Promises and use `Promise.race` to free a slot when any job finishes.
- In `executeJob`, create a timeout Promise with `new Promise<never>((_, reject) => setTimeout(...))` and race it against the handler; a `timed_out` result must exit immediately without retrying.
- When collecting `ValidationError[]` in `validateJob`, push errors into a mutable local array and only decide `ok: true` vs `ok: false` at the very end — this satisfies the 'collect ALL errors' requirement.
Useful resources
Or clone locally
git clone -b challenge/2026-05-13 https://github.com/niltonheck/typedrop.git