Spectre.Instance.CheckpointStore behaviour (Spectre v0.3.0)

Copy Markdown View Source

Durable adapter boundary for the complete canonical Agent checkpoint.

Stores should implement compare_and_swap/5. The expected revision is the last checkpoint acknowledged by the adapter and the new revision is embedded in the encoded checkpoint as well. An adapter that cannot determine whether a write committed must return {:error, {:ambiguous, reason}}; Spectre will not retry that write automatically.

Summary

Functions

Loads the checkpoint for ref from a normalized store configuration.

Atomically migrates a validated legacy Instance key to its stable key.

Normalizes a user-facing store configuration into nil (checkpointing disabled) or a canonical {module, opts} tuple.

Persists an encoded checkpoint through the adapter's compare_and_swap/5.

Types

config()

@type config() :: module() | {module(), keyword()} | false | nil

Callbacks

compare_and_swap(t, t, non_neg_integer, non_neg_integer, keyword)

(optional)
@callback compare_and_swap(
  Spectre.Instance.Ref.t(),
  String.t(),
  non_neg_integer(),
  non_neg_integer(),
  keyword()
) :: :ok | {:ok, term()} | {:error, term()}

load(t, keyword)

(optional)
@callback load(
  Spectre.Instance.Ref.t(),
  keyword()
) :: :not_found | {:ok, String.t() | map()} | {:error, term()}

migrate_instance_key(t, t, arg3, t, keyword)

(optional)
@callback migrate_instance_key(
  Spectre.Instance.Ref.t(),
  Spectre.Instance.Ref.t(),
  String.t() | map(),
  String.t(),
  keyword()
) :: :ok | {:ok, :moved | :aliased} | {:error, term()}

Functions

load(arg1, ref, opts)

@spec load(nil | {module(), keyword()}, Spectre.Instance.Ref.t(), keyword()) ::
  :not_found | {:ok, String.t() | map()} | {:error, term()}

Loads the checkpoint for ref from a normalized store configuration.

Returns :not_found when checkpointing is disabled or the adapter does not export load/2. Adapter exceptions and throws are captured and returned as {:error, term()}; invalid adapter replies are rejected as well.

migrate_instance_key(store, legacy_ref, stable_ref, legacy_checkpoint, migrated_checkpoint, opts)

@spec migrate_instance_key(
  {module(), keyword()},
  Spectre.Instance.Ref.t(),
  Spectre.Instance.Ref.t(),
  String.t() | map(),
  String.t(),
  keyword()
) :: :ok | {:error, term()}

Atomically migrates a validated legacy Instance key to its stable key.

The adapter receives both the exact legacy checkpoint observed by core and the migrated schema-2 checkpoint it must expose under stable_ref. It must reject an existing divergent target and either move the source or leave a controlled alias. Core verifies the target byte-for-byte after success.

normalize(value)

@spec normalize(config()) :: {:ok, nil | {module(), keyword()}} | {:error, term()}

Normalizes a user-facing store configuration into nil (checkpointing disabled) or a canonical {module, opts} tuple.

Returns {:error, {:invalid_checkpoint_store, value}} for anything else.

persist(arg, ref, checkpoint, expected, revision, opts)

@spec persist(
  {module(), keyword()},
  Spectre.Instance.Ref.t(),
  String.t(),
  non_neg_integer(),
  non_neg_integer(),
  keyword()
) :: :ok | {:error, term()}

Persists an encoded checkpoint through the adapter's compare_and_swap/5.

expected is the last acknowledged revision and revision the one being written. Adapter exceptions, throws, and invalid replies are mapped to {:error, {:ambiguous, reason}} because the write may still have committed.