popoto.batch¶
popoto.batch
¶
One transaction, opened without reaching for the client (#630, #759 M5).
batch() is the supported way for a recipe -- or a caller -- to open a
Popoto transaction. It returns a real redis.client.Pipeline: commands
queue until you call execute(), and everything queued applies in one
MULTI/EXEC.
The return type is deliberately the redis-py pipeline itself and not a
wrapper. Popoto's field layer decides whether a write joins the caller's
transaction with isinstance(pipeline, redis.client.Pipeline) at twenty
sites, several of them shaped pipeline if isinstance(...) else
POPOTO_REDIS_DB. A wrapper object would fail those checks silently, fall
back to the shared client, and execute immediately -- voiding the atomicity
the batch was opened for, with no error raised anywhere.
Because it is an ordinary pipeline, it is also an ordinary context manager:
with releases the connection on exit but does not execute. Call
execute() yourself.
import popoto
pipe = popoto.batch()
JournalEntry.append(agent_id="a", statement="...", pipeline=pipe)
JournalEntry.append(agent_id="a", statement="...", pipeline=pipe)
pipe.execute()
Postgres-bound models (#759 M5, plan TD-5). The pipeline is a
:class:Batch, a subclass of popoto's guarded pipeline, so everything above
holds byte for byte on Redis. A write from a model bound to Postgres that is
handed the batch joins it: the batch opens one Postgres transaction()
on that model's backend at the first such write, the write runs inside it,
and execute() commits it. It is atomic: if a statement fails inside the
transaction, nothing in the batch is written (execute() then raises),
where a Redis MULTI/EXEC applies the other queued commands. A save
refused before it sends anything (pre_save's unique check against a
committed record, a validation error) raises at the call and leaves the
batch healthy, as on Redis. reset(), leaving a
with block, or dropping the batch without execute() rolls it back,
as a Redis pipeline that is never executed sends nothing. Until execute()
other connections do not see the batch's writes, as with queued commands.
One batch, one backend. A batch that has queued Redis commands refuses a
Postgres write, and one holding a Postgres transaction refuses a Redis
command, with :class:~popoto.backends.BackendCapabilityError, before either
is sent. Two stores cannot commit atomically together, and a batch that
looked atomic but was not would be worse than a refusal. Open one batch per
backend.
Batch
¶
Bases: GuardedPipeline
The pipeline batch() returns: popoto's guarded Redis pipeline, plus
the Postgres transaction a Postgres-bound model's writes join (module
docstring). Redis commands queue and execute exactly as on any pipeline;
nothing here sends a byte to Redis that the plain pipeline would not.
Source code in src/popoto/batch.py
69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 | |
execute(raise_on_error=True)
¶
Execute the queued Redis commands -- or commit the Postgres
transaction (returning []). A Postgres batch in which a statement
failed is rolled back whole, and this raises
:class:~popoto.backends.BackendError.
Source code in src/popoto/batch.py
batch(transaction=True)
¶
Open a batch of queued commands against the shared connection.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
transaction
|
bool
|
Wrap the queued commands in |
True
|
Returns:
| Type | Description |
|---|---|
'Pipeline'
|
A |
'Pipeline'
|
(directly, or by passing it as |
'Pipeline'
|
recipe calls), then call |
Source code in src/popoto/batch.py
join_unit(pipeline, backend)
¶
What a pipeline= argument becomes for a write to backend.
A :class:Batch handed to a non-Redis backend's write returns the
batch's Postgres unit of work (opening it); handed to a Redis write while
it holds a Postgres transaction, it raises
:class:~popoto.backends.BackendCapabilityError before anything is
queued. Everything else -- a plain pipeline, a unit of work, None, a
batch for a Redis write -- returns None: the caller keeps its own
handling, unchanged.
Source code in src/popoto/batch.py
unit_of(pipeline, backend)
¶
The unit of work a non-Redis write runs in: pipeline itself when
it is one (a transaction()), the batch's when it is a
:class:Batch, else None (a plain Redis pipeline cannot carry a
Postgres write).