mirror of
https://github.com/bitechdev/ResolveSpec.git
synced 2026-10-01 04:21:58 +00:00
2.6 KiB
2.6 KiB
Request Transactions (cheatsheet)
Every DB statement and every DB-touching hook of one request runs on one transaction. Hooks never get the pool.
Rules
hookCtx.Txis always the open transaction (neverh.db), exceptBeforeHandle, which runs before any tx and must not touch the DB.OnTxBeginfires once, first, in every tx the handler opens (incl. the second short tx).OnTxBeginerror or abort: rollback, client gets a generic error, nothing leaked.- Begin or commit failure: generic error (
transaction_error/ "Transaction failed" in websocketspec, mqttspec, funcspec). - Transaction-local state (
set_config(..., true), RLS GUCs) is only visible on that tx. Set it inOnTxBegin.
Transactions per operation
| Operation | Tx 1 | Tx 2 (short, after commit) |
|---|---|---|
| read | BeforeRead, count, scan, AfterRead* |
restheadspec: AfterRead |
| create | Before*, insert |
re-fetch, BeforeScan, AfterCreate |
| update | Before*, select, update, AfterUpdate† |
re-fetch (+ AfterUpdate where noted) |
| delete (single/batch) | BeforeDelete, select, delete, AfterDelete |
none |
| funcspec query | BeforeQuery*, BeforeSQLExec, SQL, After* |
BeforeResponse |
* resolvespec, websocketspec, mqttspec, resolvemcp. restheadspec runs AfterRead in tx 2.
† restheadspec, websocketspec, mqttspec run AfterUpdate in tx 2. resolvespec, resolvemcp run it in tx 1.
Tx 2 exists so the re-fetch sees trigger changes from the committed write.
Per spec
| Spec | OnTxBegin |
Helper |
|---|---|---|
| resolvespec, restheadspec, websocketspec, resolvemcp, funcspec | own HookType = common.TxHookName |
Handler.runInTx |
| mqttspec | re-exports websocketspec.OnTxBegin |
Handler.runInTx |
common.RunRequestTx(ctx, db, TxContext, onBegin, body): open tx,SetTx,onBegin,body.common.TxContext:SetTx(tx); implemented by each spec'sHookContext.
RLS / transaction settings (pkg/security)
SecurityList.SetTxSettings(fn):fn(SecurityContext) (map[string]string, error); nil disables.- Every spec's
RegisterSecurityHooksregistersOnTxBegin→security.StampTxSettings.fnis read per call, so set order does not matter. - Stamps via
set_config(name, value, true)in name order, before any other SQL. - Fail closed:
fnerror, invalid name, or non-Postgres driver with a non-empty map aborts the tx. - Name: dotted identifier (
ns.name). Value is hex-encoded in SQL, never inlined. - Low level:
security.ApplyTxSettings(secCtx, tx, map).
Test notes
- sqlmock +
SetMaxOpenConns(1): any pool use inside an open tx blocks and fails. - restheadspec model-based updates/reads need the bun adapter.