Class InMemoryStorage
The bundled in-memory provider (ARCHITECTURE.md §4 P5) — for development, samples, and tests. Explicitly not durable. A single lock serializes every operation, which makes the atomicity contract trivially true; the value of this implementation is precision, not speed.
public sealed class InMemoryStorage : IJobStorage, IWorkflowStorage, IStorageNotifier, IMonitoringStorage
- Inheritance
-
InMemoryStorage
- Implements
- Inherited Members
Remarks
Held to exactly the same observable contract as a relational provider — ordering, cursor handling and limit clamping all match, because the conformance kit runs the same facts against both. Where the two could drift, this defers to the shared MonitoringCursor.
Constructors
- InMemoryStorage(TimeProvider?)
Creates an empty store.
Properties
- Capabilities
Optional powers this provider offers, which the engine adapts to.
Methods
- ActivateDueJobsAsync(DateTimeOffset, int, CancellationToken)
Moves due Scheduled/Failed jobs (
DueAt <= now) to Enqueued, clearing DueAt, inDueAt ASCorder (oldest first; ties by enqueue order), up tobatchSize; returns the number moved. Safe to run concurrently on every node — each job activates exactly once.
- AddBookmarkAsync(BookmarkRecord, CancellationToken)
Records that an instance is waiting for a signal.
- ApplyAsync(JobTransition, CancellationToken)
Applies an engine-computed transition atomically behind the fence (§4.2.3); false = fence rejected, nothing changed.
- ClaimAsync(ClaimRequest, CancellationToken)
Exclusively claims up to MaxCount jobs (§4.2.1–2).
- ConsumeBookmarkAsync(string, string, CancellationToken)
Atomically consumes (removes and returns) the oldest matching bookmark — ordered by CreatedAt, then Id — or returns null when none match. At-most-once under arbitrary concurrency (§4.2.4): a signal resumes exactly one waiting instance.
- CreateInstanceAsync(WorkflowInstanceRecord, CancellationToken)
Stores a new instance with
Revision = 1; duplicate id throws MillraceConcurrencyException.
- EnqueueAsync(IReadOnlyList<JobRecord>, CancellationToken)
Inserts jobs all-or-nothing and returns their effective ids positionally.
- GetDueRecurringAsync(DateTimeOffset, int, CancellationToken)
Plain read of records with
NextFireTime <= now, orderedNextFireTime ASC(most overdue first, so a backlog cannot starve old definitions), up tobatchSize.
- GetInstanceAsync(WorkflowInstanceId, CancellationToken)
Reads one instance, or null if it does not exist.
- GetJobAsync(JobId, CancellationToken)
Reads one job, or null if no such job exists.
- GetJobDetailsAsync(JobId, CancellationToken)
Full detail for one job, or null if no such job exists.
- GetRecurringAsync(string, CancellationToken)
Reads one recurring definition, or null if none is registered under that id.
- GetStatisticsAsync(TenantFilter, CancellationToken)
Aggregate counts for the overview, scoped by
tenant.
- ListenAsync(IReadOnlySet<string>, CancellationToken)
Streams wakeup hints for
queuesuntil cancelled.
- QueryInstancesAsync(InstanceQuery, CancellationToken)
One page of workflow instances matching
query. Same paging, cursor and tenancy rules as QueryJobsAsync(JobQuery, CancellationToken).
- QueryJobsAsync(JobQuery, CancellationToken)
One page of jobs matching
query.
- QueryRecurringAsync(RecurringQuery, CancellationToken)
One page of recurring definitions matching
query, orderedNextFireTime ASC, Id ASC.
- RemoveRecurringAsync(string, CancellationToken)
Removes a recurring definition.
- RenewLeasesAsync(string, IReadOnlyList<JobId>, TimeSpan, CancellationToken)
Extends leases for in-flight jobs; returns the ids actually renewed.
- TryCancelAsync(JobId, CancellationToken)
Cancels a job. Atomic: Scheduled/Enqueued/Failed/Awaiting ⇒ Cancelled (FinishedAt set, key released, transitive Awaiting-descendant cascade) and returns true; Processing ⇒ sets CancelRequested only (state and fence untouched) and returns true; terminal or unknown ⇒ false, no mutation. CancelRequested never blocks a fenced ApplyAsync(JobTransition, CancellationToken) — a completing worker may still win with Succeeded.
- TryFireRecurringAsync(string, DateTimeOffset, DateTimeOffset, JobRecord, CancellationToken)
Fenced fire (§4.2.5, strengthened): compare-and-set on (
id,expectedFireTime) advancing NextFireTime tonextFireTimeand setting LastFireTime = expected, insertingjobin the same atomic operation iff the CAS wins. Returns whether this caller won — exactly one node enqueues each occurrence, with no crash window between fence and enqueue.
- TryRunNowAsync(JobId, CancellationToken)
Makes a job that is waiting out its retry backoff claimable immediately (§11.32). Atomic: Failed ⇒ Enqueued with DueAt cleared, returning true; any other state, or unknown, ⇒ false with no mutation.
- UpdateInstanceAsync(WorkflowInstanceRecord, long, CancellationToken)
Optimistic-concurrency replace: throws MillraceConcurrencyException unless the stored revision equals
expectedRevision(a missing instance is the same failure — providers must not distinguish); on success storesRevision = expectedRevision + 1.
- UpsertRecurringAsync(RecurringJobRecord, CancellationToken)
Single atomic upsert. Insert stores the record as given. Update overwrites Cron/Queue/Invocation/Retry/Priority/TenantId/UpdatedAt; takes NextFireTime from the record iff the stored Cron differs from the record's (else preserves the stored value — the engine always passes a freshly computed NextFireTime, conditionally unused); always preserves LastFireTime/CreatedAt.