Sync Modes And Visibility

Copy Markdown View Source

Scrypath makes sync mode explicit because search visibility is an operational concern, not hidden framework magic.

The Contract

ModeWhat completed work meansWhat it does not mean
:inlineScrypath waited for terminal backend successdatabase and search writes are not atomic
:manualthe backend accepted workthe document may not be searchable yet
:obanthe enqueue is durablethe backend write has not happened yet

Accepted work is not the same thing as search visibility.

Operator lifecycle

requested -> enqueued -> processing -> backend_accepted -> completed | retrying | discarded

StateOperator meaningNot implied for search visibility
requestedWork is queued for syncNothing is durable or visible in the index yet
enqueuedThe system accepted responsibility to run the workFor :oban, this can stop at durable enqueue; search may still be stale
processingA worker or inline path is actively driving backend workReads may still return older index state
backend_acceptedThe backend acknowledged the write attemptThe document may still be behind on visibility or eventual indexing
completedTerminal success for the tracked unit of workStale reads or drift can still exist across deployments
retryingWork is being retried after a transient failureRetries do not guarantee immediate search freshness
discardedThe operator path gave up on this unit of workDeletes or tombstones may still need explicit recovery

:inline, :oban, and :manual all move records along this same chain; they differ in where your app usually observes progress—before the caller returns, after durable enqueue, or only after you take the next manual step—not in the underlying lifecycle vocabulary. See the per-mode sections below for the exact return semantics and recovery posture.

:inline

Use :inline when the write path should wait for terminal backend task success before it returns.

What you can see:

What can still fail:

  • database and search writes are still not atomic
  • later reads can still surface stale search hits if the contract changed

Recovery posture:

  • retry explicit failed work if the original contract still holds
  • backfill the live index when the index is still trustworthy
  • reindex when mappings or settings changed and the live index should not be trusted

:oban

Use :oban when durable enqueue matters more than immediate search visibility.

What you can see:

What can still fail:

  • the backend write may not have started yet
  • retry exhaustion, discarded jobs, and stale deletes are operational cases, not surprises

Recovery posture:

  • inspect retryable work first
  • use mix scrypath.retry only with one explicit failed-work id
  • move to backfill or reindex when the issue is larger than one queue replay

:manual

Use :manual when operators or migration workflows should hold the next step explicitly.

What you can see:

  • accepted backend work
  • the current live/target index posture through mix scrypath.reconcile
  • the same report-first guidance as the other modes

What can still fail:

  • accepted work does not mean the document is searchable yet
  • manual follow-up can drift from the source of truth if nobody closes the loop

Recovery posture:

  • use status and reconcile to decide whether the live index is still sound
  • prefer backfill when the contract is unchanged
  • prefer reindex when the contract changed or rebuild visibility is already pointing at a target index

Phoenix Implications

This wording matters in Phoenix because a controller response, JSON payload, or LiveView state update can easily over-promise what happened.

  • A successful controller action can mean repo write succeeded while search visibility is still pending
  • A LiveView update can reflect database state before async search work completes
  • An Oban-backed flow means the durable enqueue succeeded, not that the search backend finished

The recommended boundary is still the same: let the context choose the mode, then let the controller or LiveView present the outcome honestly.

Where To Put The Decision

Choose sync mode in the context that owns the feature. That keeps consistency and recovery tradeoffs close to the repo write and close to the operator workflow that will respond when drift appears.

Recovery Still Matters

Retries, stale deletes, and drift are normal operator concerns. When the live index contract is still correct, backfill into the live index. When the contract changed or you do not trust the live index, rebuild into a target index and review before cutover.

The thin CLI wrappers in guides/operator-mix-tasks.md exist to make those checks easy from a terminal, but the real operator contract still lives on Scrypath.*.