Start

Create an execution

{:ok, execution, state} =
  Executions.create(store, "loan_01H8", machine,
    executor: executor,
    initialize: [invoke_types: invoke_types, send_types: send_types]
  )

The execution id is yours. Creating an id that exists answers {:error, :execution_exists}. See How to persist an execution and resume it in another process.

Create options

OptionDefaultMeaning
executor:requiredReceives each effect, in order
initialize:[]Passed to the interpreter; routes:, invoke_types:, send_types: and function_providers: go here
metadata:%{}Host identities stored on the record
serialization:the adapter's lock{module, config} ordering strategy

Step

Deliver one event

{:ok, execution, state} =
  Executions.step(store, "loan_01H8", machine,
    Event.external("loan.due"), executor: executor)

Answers

{:ok, execution, state}
{:discarded, execution}
{:error, {:needs_migration, execution}}
{:error, {:identity_mismatch, stored, supplied}}

Step options

OptionDefaultMeaning
executor:requiredReceives each effect
routes:nilLive <send> targets for this step
invoke_types:nilBuilt-in set only
send_types:nilUnregistered <send> types are rejected
function_providers:nilHost functions for cond and expr
serialization:the adapter's lock{module, config}

End from the host

Executions.fail(store, "loan_01H8", "copy lost")
Executions.cancel(store, "loan_01H8")

Resume

Another process, one id

{:ok, record} = Storage.fetch_execution(store, "loan_01H8")
{:ok, %{chart_blob: blob}} = Storage.fetch_chart(store, record.content_hash)
{:ok, machine} = Chart.from_binary(blob)

Then Executions.step/5 with that machine. See How to persist an execution and resume it in another process.

Store the chart first

{:ok, machine} = Statifier.compile(source)
{:ok, chart_blob} = Chart.to_binary(machine)
:ok = Storage.save_chart(store, machine, chart_blob)

Ecto adapter

Persistence module

defmodule MyApp.Persistence do
  use StatifierPersistence.Ecto, repo: MyApp.Repo
end

Migration

def up, do: StatifierPersistence.Ecto.Migrations.up(for: MyApp.Persistence)
def down, do: StatifierPersistence.Ecto.Migrations.down(for: MyApp.Persistence)

from: and version: bound the span, in both directions.

Guarded store

{:ok, store} =
  Storage.new(StatifierPersistence.Storage.Ecto,
    persistence: MyApp.Persistence)

Store options

OptionDefaultMeaning
persistence:requiredModule that called use StatifierPersistence.Ecto
input_log_cap::infinityPer-execution cap on the input log
sandbox:falseCheck out an Ecto sandbox connection per test

use options

OptionDefaultMeaning
repo:requiredYour Ecto.Repo
key::uxid:uuid, :bigserial or {module, opts}
table_prefix:"statifier_"Prefix of the table names
tables:%{}Per-table name override
prefix:nilPostgres schema
blob_type::binaryEcto type of the payload columns
leading_columns:[]Host columns placed after id
timestamps_position::trailingOr :leading
column_collations:[]Collation per text column

See How to set up the Ecto adapter.

Retire

Retire a chart

Executions.retire_chart(store, content_hash, [MyApp.TimerPins],
  retired_by: "ops@example.test")

Answers

{:ok, %{content_hash: _, retired_at: _, retired_by: _}}
{:error, {:pinned, counts}}
{:error, {:pin_source_failed, {module, reason}}}
{:error, :chart_retirement_unsupported}

Options

OptionDefaultMeaning
retired_by:requiredOpaque string recorded on the row
now:DateTime.utc_now/0Written as retired_at

Pin source

@behaviour StatifierPersistence.PinSource

def pins(content_hash, %{execution_ids: ids}),
  do: %{pending_timers: MyApp.Timers.count_scheduled_for(ids)}

See How to retire a chart and prune finished executions.

Prune

Prune finished executions

{:ok, %{executions: _, position_blobs: _, inputs: _}} =
  StatifierPersistence.Retention.prune(store, cutoff)

cutoff is a DateTime; a duration raises ArgumentError.

Options

OptionDefaultMeaning
batch_size:500Executions per batch
scope:whole storeColumn equalities, such as [tenant_id: "a"]
single_batch:falseOne batch, answers more?

See What a finished execution leaves behind.