Table of Contents

Conformance facts

Generated file — do not edit. Rendered from the conformance suites by scripts/generate-conformance-facts.ps1. Change the suites, then run it.

A provider that passes these is a supported provider. There are 110 of them, and they are the definition rather than a description of it — Writing a provider explains what you implement, and this is what gets checked.

Each line is a test method name with its underscores replaced by spaces, in source order. Put the underscores back to find one in Millrace.Storage.Verification, or to run it on its own. 5 of them are theories, so a run reports more cases than there are lines here.

Nothing on this page was written for it. If a sentence below is unclear, the fix belongs in the method name it came from.

Job storage — JobStorageConformanceSuite (64 facts)

Checkpoints

  • Checkpoint transition and enqueue all commit together
  • A stale checkpoint revision rolls back the whole transition
  • A checkpoint for a missing instance rolls back the whole transition
  • A fence rejection leaves the instance untouched
  • Concurrent branch checkpoints have exactly one winner
  • A transition without a checkpoint still behaves as before

Continuations

  • Parent success activates direct awaiting children only
  • Parent death cancels the transitive awaiting closure and releases keys
  • Active children shield their descendants from the cancel cascade
  • Awaiting insert after parent succeeded is fixed up to enqueued
  • Awaiting insert after parent death is fixed up to cancelled
  • Awaiting insert after parent cancellation is fixed up to cancelled
  • Awaiting insert with missing parent throws and rolls back the batch
  • Awaiting inserts racing parent terminal apply never strand a child (theory)

Idempotency keys

  • Duplicate active key is a noop returning the existing id
  • Concurrent same key enqueues yield exactly one job
  • Key uniqueness is scoped per tenant with null as its own scope
  • Terminal transition frees the key but retains the field
  • Enqueue racing terminal release always returns a valid id
  • Apply enqueue insert with duplicate active key is skipped as noop
  • Terminal key release is visible to the same transitions enqueue inserts

Batches

  • Enqueue returns effective ids positionally
  • Enqueue batch with duplicate job id throws and persists nothing

Cancellation

  • TryCancel pre active states cancel with cascade and key release (theory)
  • TryCancel processing sets flag only and never blocks the fence
  • TryCancel racing fenced apply yields exactly one terminal outcome
  • TryCancel racing activation and claim yields exactly one owner
  • TryCancel terminal and unknown jobs return false without mutation

Claims and leases

  • Claim is exclusive under contention
  • Claim sets processing worker lease and increments attempt
  • Claim returns at most max count
  • Claim only returns requested queues
  • Unexpired lease blocks reclaim
  • Expired lease is reclaimable and increments attempt
  • Claim order is priority desc then fifo across queue union
  • Scheduled failed and awaiting jobs are never claimable directly

Lease renewal

  • Renew extends lease beyond original expiry
  • Renew resurrects expired but unreclaimed lease
  • Renewal racing reclaim has exactly one owner
  • GetJob roundtrips every field
  • Renew excludes jobs reclaimed by another worker

The apply fence

  • Apply with wrong worker is rejected without changes
  • Apply with wrong attempt is rejected without changes
  • Apply zombie versus new owner exactly one wins
  • Apply succeeded sets terminal fields
  • Run now makes a retrying job claimable without spending retry budget
  • Run now refuses anything not awaiting a retry (theory)
  • Run now on an unknown job reports false
  • Apply failed schedules retry and activation makes it claimable
  • Apply release returns job to queue without consuming retry budget
  • Apply is all or nothing when an enqueue insert fails
  • Apply enqueue inserts commit atomically with the transition

Due activation

  • Activate moves only due jobs oldest first respecting batch size
  • Concurrent activation activates each job exactly once

Recurring

  • Recurring upsert roundtrips all fields
  • Recurring upsert with same cron preserves next fire time
  • Recurring upsert with changed cron takes the records next fire time
  • GetDueRecurring returns due only within batch limit
  • Activation breaks due time ties by enqueue order
  • TryFire cas has exactly one winner and one enqueued job
  • TryFire with stale expected time returns false and inserts nothing
  • TryFire unknown id returns false
  • Remove recurring removes the definition
  • Same cron upsert racing fire never rewinds next fire time

Workflow storage — WorkflowStorageConformanceSuite (11 facts)

  • Create and get roundtrip with revision one
  • Create normalizes revision to one regardless of input
  • Duplicate create throws concurrency exception
  • Update with matching revision increments it
  • Update with stale revision throws and changes nothing
  • Update of missing instance throws concurrency exception
  • Concurrent updates have exactly one winner
  • Consume with no match returns null
  • Consume is at most once under contention
  • Consume returns the oldest matching bookmark
  • Consume breaks created at ties by id

Monitoring read model — MonitoringConformanceSuite (35 facts)

  • Query orders newest first
  • Paging walks every row exactly once
  • Last page reports a null cursor
  • Empty result has no items and no cursor
  • Paging is stable when rows change state underneath
  • An undecodable cursor is rejected rather than restarting (theory)
  • Limit is clamped never rejected
  • State filter selects only those states
  • Empty state list means any state
  • Queue and created range filters combine with and
  • Created range is lower inclusive and upper exclusive
  • Tenant filter distinguishes any from untenanted
  • Job details returns null for an unknown id
  • Job details carries the payload the summary omits
  • Interruptions separate infrastructure churn from recorded failures
  • Statistics report every state including zeroes
  • Statistics respect the tenant filter
  • Statistics count recurring definitions and overdue ones
  • Recurring definitions are ordered soonest first
  • A job that succeeds first time records no attempt history
  • A failed attempt is recorded with its error and worker
  • An expired lease records an interruption rather than a failure
  • A fenced release records an interruption
  • Attempt history is newest first and capped without distorting the counters
  • A definition that has never fired reports no last outcome
  • The last outcome is the state of the most recently created fired job
  • A running occurrence outranks an earlier success
  • The link to a definition survives the definition being removed
  • Recurring paging walks every definition exactly once
  • Recurring ties on fire time break by id
  • Recurring filters by queue and tenant and clamps the limit
  • Recurring rejects an undecodable cursor (theory)
  • Recurring summary carries schedule fields and no outcome
  • Instance queries page and filter like job queries
  • Instance version filter requires a definition id