django_subatomic.db ¶
transaction ¶
transaction(*, using: str | None = None) -> Generator[None]
Create a database transaction.
Can be used as a decorator or a context manager.
Nested calls are not allowed because SQL does not support nested transactions.
Consider this like Django's atomic(durable=True)
, but with added after-commit callback support in tests.
Raises:
Type | Description |
---|---|
RuntimeError
|
if we call this from inside another existing transaction. |
Source code in django_subatomic/db.py
31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
|
transaction_if_not_already ¶
transaction_if_not_already(*, using: str | None = None) -> Generator[None]
Create a transaction if one isn't already open.
Can be used as a decorator or a context manager.
Use of this hints at code which lacks control over the state it's called in.
Note
This has a bit of a clunky name. This is a deliberate attempt to discourage its use. It acts as a code-smell to highlight that places which use it may need further work to achieve full control over how transactions are managed.
Warning
If this function is called when a transaction is already open, errors raised through it will invalidate the current transaction, regardless of where it was opened.
Suggested alternatives
-
In functions which should not control transactions, use
transaction_required
. This ensures they are handled by the caller. -
In functions which can unambiguously control transactions, use
transaction
.
Source code in django_subatomic/db.py
53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 |
|
savepoint ¶
savepoint(*, using: str | None = None) -> Generator[None]
Create a database savepoint.
Can be used as a context manager, but not as a decorator.
Must be called inside an active transaction.
Recommended usage
- You should only create a savepoint if you may roll back to it before
continuing with your transaction. If your intention is to ensure that
your code is committed atomically, consider using
transaction_required
instead. - We believe savepoint rollback should be handled where the savepoint is created. That locality is not possible with a decorator, so this function deliberately does not work as one.
Raises:
Type | Description |
---|---|
_MissingRequiredTransaction
|
if we are not in a transaction |
Source code in django_subatomic/db.py
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 |
|
transaction_required ¶
transaction_required(*, using: str | None = None) -> Generator[None]
Make sure that code is always executed in a transaction.
Can be used as a decorator or a context manager.
We ignore test-suite transactions when checking for a transaction because we don't want to run the risk of allowing code to pass tests but fail in production.
Raises:
Type | Description |
---|---|
_MissingRequiredTransaction
|
if we are not in a transaction. |
Source code in django_subatomic/db.py
121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 |
|
durable ¶
durable[**P, R](func: Callable[P, R]) -> Callable[P, R]
Enforce durability with this decorator.
Can be used as a decorator, but not as a context manager.
"Durability" means that the function's work cannot be rolled back after it completes, and is not to be confused with "atomicity" (which is about ensuring that the function either completes all its work or none of it).
We enforce this by ensuring that the function is not called within a transaction, and that no transaction is left open when the function completes.
Raises:
Type | Description |
---|---|
_UnexpectedOpenTransaction
|
if a transaction is already open when this is called. |
_UnexpectedDanglingTransaction
|
if a transaction remains open after the decorated function exits. Before raising this exeption, we roll back and end the transaction. |
Source code in django_subatomic/db.py
143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 |
|
run_after_commit ¶
run_after_commit(callback: Callable[[], object], *, using: str | None = None) -> None
Register a callback to be called after the current transaction is committed.
(Transactions created by the test suite are deliberately ignored.)
If the current transaction is rolled back, the callback will not be called.
By default, an error will be raised if there is no transaction open.
While you are transitioning your codebase to stricter transaction handling,
you may disable this with settings.SUBATOMIC_AFTER_COMMIT_NEEDS_TRANSACTION
.
Note
Django's on_commit
has a robust
parameter, which allows a callback
to fail silently. Kraken has a convention to "not allow code to fail
silently" so this behaviour is not available from this function.
Source code in django_subatomic/db.py
316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 |
|
in_transaction ¶
in_transaction(*, using: str | None = None) -> bool
Return True
if the database connection has a transaction active.
A transaction is active if the connection is no longer in autocommit mode.
So that code doesn't need to handle how testcase transactions work, testcase transactions are not considered a transaction.
Source code in django_subatomic/db.py
378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 |
|
dbs_with_open_transactions ¶
dbs_with_open_transactions() -> frozenset[str]
Get the names of databases with open transactions.
Source code in django_subatomic/db.py
414 415 416 417 418 419 420 421 422 423 424 425 |
|