Skuld.Effects.Transaction (skuld v0.23.0)
View SourceTransaction effect — env state rollback with optional database transactions.
Provides transactional semantics for computations: on normal completion the transaction commits (env state preserved); on explicit rollback or sentinel (Throw, Suspend, etc.) the transaction rolls back (env state restored to pre-transaction values, with optional preservation of specified keys).
Why a separate effect?
Transactions are orthogonal to persistence. A computation may need transactional env state rollback without any database involvement (e.g. rolling back Writer accumulations on error), or it may combine transactions with domain-specific persistence Ports.
Operations
# Wrap a computation in a transaction
result <- Transaction.transact(comp do
_ <- do_some_work()
return(:ok)
end)
# Explicitly roll back the current transaction
_ <- Transaction.rollback(:reason)Handlers
Ecto (real database transaction + env state rollback):
computation
|> Transaction.Ecto.with_handler(MyApp.Repo)
|> Comp.run!()Noop (env state rollback only, no database):
computation
|> Transaction.Noop.with_handler()
|> Comp.run!()Rollback Semantics
On rollback (explicit or sentinel), env.state is restored to
pre-transaction values. Use :preserve_state_on_rollback to opt
specific state keys out of rollback (e.g. metrics, error counters).
Nested Transactions
Nested transact calls create savepoints (Ecto handler) or
independent rollback scopes (Noop handler):
comp do
result <- Transaction.transact(comp do
_ <- do_outer_work()
inner <- Transaction.transact(comp do
_ <- do_inner_work()
return(:inner_done)
end)
return({:outer_done, inner})
end)
return(result)
end
Summary
Functions
Run a computation in a transaction, returning {:ok, result} on commit
or {:rolled_back, reason} on rollback.
Functions
@spec try_transact(Skuld.Comp.Types.computation()) :: Skuld.Comp.Types.computation()
Run a computation in a transaction, returning {:ok, result} on commit
or {:rolled_back, reason} on rollback.
This is a convenience for pattern matching on the transaction outcome without needing to know whether the result is a normal value or a rollback tuple.
Example
case Transaction.try_transact(inner_comp) do
{:ok, value} -> handle_success(value)
{:rolled_back, reason} -> handle_rollback(reason)
end