TypeDrop
2026-05-07 Challenge
2026-05-07
Medium
Typed Job Queue Scheduler
You're building the background-job layer for a workflow automation platform. Raw job definitions arrive as `unknown` from a user-facing API; your scheduler must validate them, assign each job to a typed priority lane, execute lanes with a configurable concurrency limit, and return a strongly-typed execution report — with zero `any`.
Goals
- Implement `validateJob` to safely narrow an `unknown` value into a typed `Job`, returning `null` for any schema violation.
- Implement `buildQueues` to validate an array of unknowns and bucket valid jobs into a `PriorityQueues` Record by priority lane.
- Implement `executeLane` to run jobs with a sliding-window concurrency limit, capturing both successes and failures without propagating rejections.
- Implement `runScheduler` to orchestrate the full pipeline — validate, queue, execute lanes sequentially in priority order, and return a typed `SchedulerReport`.
challenge.ts
// Key types & main entry point — challenge.ts (preview)
export type Priority = "high" | "normal" | "low";
export interface Job {
id: string;
name: string;
priority: Priority;
durationMs: number;
payload: Record<string, string | number | boolean>;
}
export type PriorityQueues = Record<Priority, Job[]>;
export type JobResult =
| { status: "success"; jobId: string; jobName: string; durationMs: number }
| { status: "failure"; jobId: string; jobName: string; reason: string };
export type JobRunner = (job: Job) => Promise<
Extract<JobResult, { status: "success" }>
>;
// Your four tasks:
export function validateJob(raw: unknown): Job | null { /* TODO */ }
export function buildQueues(rawJobs: unknown[]): PriorityQueues { /* TODO */ }
export async function executeLane(
jobs: Job[], runner: JobRunner, concurrency: number
): Promise<JobResult[]> { /* TODO */ }
export async function runScheduler(
rawJobs: unknown[], runner: JobRunner, concurrency?: number
): Promise<SchedulerReport> { /* TODO */ }
Hints (click to reveal)
Hints
- For `executeLane`, maintain an in-flight `Set` of Promises and use a drain loop — or process jobs in fixed-size chunks with `Promise.allSettled` — to respect the concurrency cap while preserving result order.
- In `validateJob`, check `payload` values with `Object.entries` and verify each value's type with `typeof` — remember that `typeof null === 'object'`, so guard against that first.
- Use the `status` discriminant on `JobResult` to narrow inside `runScheduler` when tallying `succeeded`, `failed`, and `totalSuccessfulDurationMs` — no type assertions needed.
Useful resources
Or clone locally
git clone -b challenge/2026-05-07 https://github.com/niltonheck/typedrop.git