5. Roll back related writes
Creating two tasks can be one application operation. If it fails after both writes, you may need to discard both. Catching an exception after two separate service calls does not undo changes those calls have already committed.
DataR provides a shared data context. Pass the same datar to both calls so
their work settles when that context exits. This example uses one SQL signpost
and one SQLite database for both writes.
Compare the two boundaries
Reuse the service and database setup from the previous step.
The first pair of calls uses the per-call contexts from that setup. The deletes
reset the example before the second pair uses an explicit shared context.
Save this program as docs_src/tutorial/transactions.py.
"""Compare committed service calls with two writes rolled back together."""
import asyncio
from docs_src.data.common import Task, database
from docs_src.data.quickstart import tasks
from fastsprout.data import DataR
async def main() -> None:
async with database():
try:
await tasks.create(Task(id=1, title="Write documentation"))
await tasks.create(Task(id=2, title="Review documentation"))
raise ValueError("Stop this operation")
except ValueError:
separate_count = await tasks.count()
assert separate_count == 2
print("Separate calls after error:", separate_count)
await tasks.delete(1)
await tasks.delete(2)
try:
async with DataR() as datar:
await tasks.create(
Task(id=1, title="Write documentation"), datar=datar
)
await tasks.create(
Task(id=2, title="Review documentation"), datar=datar
)
raise ValueError("Stop this operation")
except ValueError:
shared_count = await tasks.count()
assert shared_count == 0
print("Shared context after error:", shared_count)
if __name__ == "__main__":
asyncio.run(main())
Run it from your tutorial directory:
Result
Why the results differ
The separate calls each finish successfully before the exception is raised. Their changes remain committed, so the subsequent count is two.
Inside async with DataR(), both service calls receive datar=datar. Their
entity uses the same signpost, so they share one SQL session. The exception
leaves the context, which aborts its work. A later count in a new context sees
zero tasks: both writes were rolled back.
Catch the exception outside the async with block, as shown. Normal exit
finalizes the context's work. If you handle an exception inside the block and
then leave normally, the context sees a successful exit.
Choose a shared context around the application operation whose writes should settle together. For more on session lifetime and multiple signposts, see What DataR owns.
Previous: Entity operations · Next: Select and page pending tasks