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
endActivities 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. Results therefore must not
contain PIDs, references, ports, or functions; an invalid result becomes a
non-retryable activity failure with a path-aware
Continuum.DurableTermError.
Execution policy is normalized by Continuum.Activity.Policy. Invalid
module defaults fail compilation; invalid call-site overrides or
idempotency keys fail the workflow before durable work is scheduled.
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
@type duration() :: {:seconds | :minutes | :hours, pos_integer()}
@type retry_policy() :: keyword()
Callbacks
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.
@callback run(Continuum.Activity.Context.t(), any()) :: {:ok, term()} | {:error, term()}