Continuum.Activity behaviour (continuum v0.5.0)

Copy Markdown View Source

Defines an activity — the only place where side effects are allowed.

defmodule Payments.Charge do
  use Continuum.Activity,
    retry: [max_attempts: 5, backoff: :exponential, base_ms: 500],
    timeout: {:seconds, 30}

  @impl true
  def run(order_id, amount) do
    Stripe.charge(order_id, amount)
  end
end

Activities are not subject to the determinism scanner — they can do arbitrary I/O, talk to NIFs, raise, etc. Their return value is journaled on first success and replayed on workflow resume.

Implementing the optional idempotency_key/1 callback stores the key in the durable task payload. Once an activity result has been committed, another task for the same activity module and key reuses that committed result without running the activity body again. This suppresses duplicate execution after Continuum has recorded success; external systems should still receive the same key because a worker can crash after the side effect succeeds but before Continuum commits the result.

Summary

Callbacks

Returns a stable idempotency key for a scheduled activity call, or nil.

Types

duration()

@type duration() :: {:seconds | :minutes | :hours, pos_integer()}

retry_policy()

@type retry_policy() :: keyword()

Callbacks

idempotency_key(any)

(optional)
@callback idempotency_key(any()) :: binary() | nil

Returns a stable idempotency key for a scheduled activity call, or nil.

Keys are scoped by activity module, not by run. Any run invoking the same activity module with the same key receives the same committed result.

run(any)

(optional)
@callback run(any()) :: {:ok, term()} | {:error, term()}