TypeDrop

2026-06-09 Challenge

2026-06-09 Medium

Typed Job Queue Scheduler with Priority & Concurrency

You're building the background-job engine for a data-processing platform. Raw job definitions arrive as `unknown` from a REST API; your scheduler must validate them, dispatch jobs by priority through a typed concurrency-limited runner, and return a strongly-typed execution report — with zero `any`.

Goals

  • Define a three-variant discriminated union `JobDefinition` and a generic `Result<T, E>` type with no `any`.
  • Implement `parseJobDefinition` that narrows `unknown` input to the correct `JobDefinition` variant or returns a descriptive error string.
  • Build a `JobHandlerMap` mapped type using `Extract` and implement the concurrency-limited `runScheduler` that sorts jobs by priority and caps parallel execution.
  • Ensure `runScheduler` returns a fully-typed `SchedulerReport` that accounts for both parse failures and runtime handler errors.
challenge.ts
// Key types & main function signature

type Priority = "critical" | "high" | "normal" | "low";

// Discriminated union — three variants sharing a `kind` discriminant
type JobDefinition =
  | { readonly kind: "http";         readonly id: string; readonly priority: Priority; /* ... */ }
  | { readonly kind: "compute";      readonly id: string; readonly priority: Priority; /* ... */ }
  | { readonly kind: "notification"; readonly id: string; readonly priority: Priority; /* ... */ };

// Generic Result monad
type Result<T, E> = /* { ok: true; value: T } | { ok: false; error: E } */;

// Mapped type: one async handler per job kind
type JobHandlerMap = {
  [K in JobDefinition["kind"]]: (job: Extract<JobDefinition, { kind: K }>) => Promise<void>;
};

// Validates unknown input → typed JobDefinition or error string
function parseJobDefinition(raw: unknown): Result<JobDefinition, string> { /* ... */ }

// Validates, sorts by priority, runs up to `concurrency` jobs in parallel
async function runScheduler(
  rawJobs: unknown[],
  options: { concurrency: number; handlers: JobHandlerMap }
): Promise<SchedulerReport> { /* ... */ }
Hints (click to reveal)

Hints

  • For `JobHandlerMap`, use a mapped type over `JobDefinition["kind"]` combined with `Extract<JobDefinition, { kind: K }>` to get the exact variant type per handler.
  • For the concurrency limiter in `runScheduler`, maintain a counter of active jobs and a queue; resolve slots as each job settles — or consider using a Promise pool pattern.
  • In `parseJobDefinition`, narrow `kind` with a switch statement first, then validate kind-specific fields inside each case — this keeps TypeScript's narrowing happy without any type assertions.

Or clone locally

git clone -b challenge/2026-06-09 https://github.com/niltonheck/typedrop.git