Skip to main content

Module write_tx

Module write_tx 

Source
Expand description

The write transaction: one database transaction around everything a write does.

A repository write commits on its own, statement by statement: a create commits, and only then does the service run its after-hooks and publish its events. A crash between the two loses the effect, and a hook that fails afterwards cannot undo the row. in_write_tx closes that gap. It opens one transaction, publishes it as a task-local, and commits it only when the whole write succeeds; every repository write path and every scoped statement helper then runs on it instead of committing by itself.

Behaviour without a write transaction is exactly what it was: a hand-written caller that never opens one sees no change.

§Which connection

  • When a request scope holds a dedicated connection (with_request_scope or the org request scope), the transaction is begun on that connection. The fence variables it carries (company, org units, acting unit, audit attribution) were set at session level, so they hold inside the transaction without being set again, and ID-only lookups stay fenced.
  • Otherwise a pool connection is taken, the transaction is begun, and the company scope of the task, the org scope and the audit attribution are bound transaction-locally, as bind_current_company does for a bulk write.

Row-level security therefore decides inside the transaction exactly what it decided outside. A row it refuses refuses the write and, since Postgres aborts the transaction, the whole of it.

§Nesting and savepoints

A write transaction opened while one is already active joins it as a savepoint: if the inner work fails, only the inner work is undone and the outer transaction can carry on; if the inner work succeeds, its effects wait for the outer commit. The bulk repository paths use the same mechanism, so a bulk write that fails inside a service’s transaction rolls back its own rows and reports the error without poisoning anything the caller already holds.

§Cancellation

If the future running inside in_write_tx is dropped (a client disconnect, a timeout layer), the transaction is rolled back by a task spawned from the guard’s Drop, and the connection is closed instead of returned to the pool if that rollback fails. A transaction never returns to the pool open.

§Reading through it

While a write transaction is active, request_conn answers with its connection, so every scoped read and write helper of this crate, and every repository method, sees the transaction’s own uncommitted rows. Code that opens a connection of its own (a bare pool.begin() inside a hook) does not, and cannot see them: that is the one behaviour a hook has to know about.

Structs§

WriteTx
The write transaction of the current task: a handle to the connection it runs on.
WriteTxConn
The connection of a write transaction, locked. Dereferences to the Postgres connection.

Enums§

WriteTxFailure
Why a write transaction run through in_write_tx_result failed: the work’s own error, or the database while beginning, binding the scope or committing.

Functions§

current_write_tx
The write transaction of the current task, if in_write_tx opened one.
in_write_tx
Run f inside one transaction: committed when f returns Ok, rolled back when it returns Err or is dropped.
in_write_tx_result
in_write_tx for work whose error type cannot absorb a sqlx::Error: the two kinds of failure stay apart in WriteTxFailure, so a caller maps each as it must.
in_write_tx_scope
Whether the current task runs inside a write transaction.