Problemconcurrent worker scheduler

Session: Sign in to solve

Solution.txt

Job Scheduler

Problem

A background-processing service has a fixed number of workers. Jobs become eligible at a scheduled time, but a worker must claim an occurrence before running it. Recurring jobs use fixed-delay scheduling, so their next occurrence depends on when the current one completes rather than when it was originally due.

Design JobScheduler to store one-time and recurring jobs and coordinate claims from worker threads sharing one instance. Time is represented by caller-supplied logical ticks.

Requirements

  • Register timed work. submitOnce creates one occurrence due at runAt; submitRecurring creates its first occurrence due at firstRunAt and retains intervalTicks.
  • Claim only due work. claimDue(now) returns and activates any scheduled job whose due tick is at most now, or returns the empty string when none is immediately claimable.
  • Protect claims and capacity. Each job has at most one active occurrence, no occurrence can be claimed twice, and the total number of active claims never exceeds workerCount; a claim at full capacity returns the empty string.
  • Complete an occurrence. complete releases the active claim, ends a one-time job, and schedules a recurring job's next occurrence at completedAt + intervalTicks.
  • Coordinate threads. Every public call is linearizable when threads share one scheduler. Calls may use ordinary internal synchronization, but they do not wait for time, capacity, work, or completion; claimDue returns immediately when it cannot claim.

API

SignatureReturnsBehavior
JobScheduler(workerCount: integer)Not applicableCreates an empty scheduler with the given active-claim capacity.
submitOnce(jobId: string, runAt: integer)voidRegisters one-time work.
submitRecurring(jobId: string, firstRunAt: integer, intervalTicks: integer)voidRegisters fixed-delay recurring work.
claimDue(now: integer)stringAttempts an immediate claim and returns a job ID or the empty string.
complete(jobId: string, completedAt: integer)voidCompletes that job's active occurrence.

Examples

With JobScheduler(1):

StepOperationResult
1submitRecurring("pulse", 5, 4)void
2claimDue(4)""
3claimDue(5)"pulse"
4claimDue(100)""
5complete("pulse", 9)void
6claimDue(12)""
7claimDue(13)"pulse"

With two due jobs, capacity 2, and three concurrent claimDue(0) calls, exactly two calls return distinct job IDs and the other returns "".

Constraints

  • 1 <= workerCount <= 64.
  • Each jobId is non-empty, has at most 64 characters, and is submitted exactly once.
  • Tick arguments are exact nonnegative 64-bit integers no greater than 1,000,000,000,000.
  • 1 <= intervalTicks <= 1,000,000,000,000, and each computed next due tick is at most 2,000,000,000,000.
  • complete is called only for an active occurrence, with completedAt at least the tick used to claim it.
  • At most 100,000 jobs and 200,000 public method calls occur in one testcase.
  • Inputs satisfy these constraints; behavior outside them is not judged.

Notes

Calls in one thread take effect in program order. Across threads, any linearizable interleaving is valid. When several jobs are due, any one may be returned; no priority, fairness, wake-up, cancellation, or shutdown behavior is required.

PRIVATE WORKSPACE

Checking your session…

The statement is public. The editor, editorial, submissions, and saved work are private.