InMemoryJobStore
An in-process, non-persistent JobStore. Backs single-process usage and the test suite; all state is lost on restart. All time comparisons use the injected clock, which plays the role database time plays for a real backend, so tests can drive time deterministically.
Passing ephemeral = true is the caller's explicit acknowledgment that losing every job on restart is intended, as for cache warming or non-critical notifications. It changes nothing about how the store behaves; it only tells host integrations such as the Ktor plugin to log a one-line INFO at startup instead of the loud warning they emit for an unacknowledged in-memory store outside development mode.
Multi-replica caveat: the store holds no state outside its own process, so nothing is shared between instances. Every instance runs its own copy of every recurring schedule, so two or more replicas mean duplicate fires (the same as Spring's @Scheduled), and the dashboard on one instance sees only that instance's jobs. Use a shared, persistent store when more than one instance runs.
Parameters
Source of time for every comparison the store makes.
True when the caller deliberately accepts that all jobs are lost on restart. Defaults to false, which hosts treat as "the store may have been left at its default by mistake". It has no effect on store behavior.
Functions
Claims up to limit due jobs for worker under a lease of lease, scanning queues in list order (declared order is priority) and returning only jobs whose kind is in kinds. Rows of any other kind are left untouched: not claimed, not transitioned, not counted against limit. An empty kinds returns an empty list. The filter is what lets a worker that does not bind a kind (an older version mid-rollout, a fleet that drains a shared queue for a subset of kinds) leave that job for a worker that does.
Applies one claimed fire ATOMICALLY: inserts runs with enqueue semantics (including the uniqueKey rule), advances the schedule's nextFireAt to nextFireAt (null makes the schedule dormant), sets lastFiredAt to the store's clock, and releases the lease, all in one transaction. Compare-and-set on fence: returns null and changes NOTHING, inserts no runs, when the stored fence differs. On success returns the run ids in runs order, existing ids on uniqueKey dedup, exactly like enqueue. An empty runs is a legal completion (a misfire handled with Skip, for example) and returns an empty list.
Claims up to limit due schedules for worker under a lease of lease, soonest next-fire first. A schedule is due when its stored nextFireAt is non-null and not in the future by the STORE's own clock; no SPI method accepts caller-supplied time for comparisons, because the caller's clock is never authoritative. Only rows whose id is in ids are returned; other rows are left untouched, so a node only ever fires schedules it holds a definition for (the schedule analogue of claim's kind filter). An empty ids returns an empty list.
Persists jobs and returns their ids in the same order. A job whose NewJob.runAt is not in the future by the store's clock is stored as JobState.Enqueued (due, visible to workers); a future NewJob.runAt is stored as JobState.Scheduled (waiting for its time). Promoting Scheduled to Enqueued when that time arrives is the store's concern; the runtime never depends on it, because claim decides due-ness by time, not state. A uniqueKey conflict with a non-terminal job returns that job's id (see interface KDoc).
Extends the lease of running jobs. Ignores ids whose lease this worker no longer holds, including the worker's OWN ids whose lease has already expired: an expired lease is not held, even by its former owner. Reviving an expired job goes through claim, never through heartbeat.
Test hook: reads a schedule's mutable fields without reflection. Null when id is unknown.
Test hook: reads a job's mutable fields without reflection. Null when id is unknown.
Deletes terminal runs past their retention. Runs as a built-in recurring job.
Registers or reconciles code-defined schedules, once per runtime start. Per spec: an unknown ScheduleSpec.id inserts the row with nextFireAt = fireAt; a known id with an EQUAL fingerprint updates nothing (timing state is preserved across restarts); a known id with a DIFFERENT fingerprint overwrites kind, fingerprint and description, sets nextFireAt = fireAt, clears any lease, AND bumps the fence: a claim taken under the old definition must not be completable, because its runs and next fire time were computed from a definition that no longer exists. Last writer wins; concurrent upserts from nodes running different code versions are expected during rolling deploys. Upsert never deletes: a schedule removed from code keeps its row and simply stops being fired, because no node passes its id to dueSchedules.