Ticket #13870: 13870.diff

File 13870.diff, 3.2 KB (added by timo, 3 years ago)
  • docs/topics/db/transactions.txt

    diff --git a/docs/topics/db/transactions.txt b/docs/topics/db/transactions.txt
    index 4a52c5a..6e185c3 100644
    a b after catching an exception. For example:: 
    377377    there is no database transaction at all. The ``autocommit`` decorator
    378378    still uses transactions, automatically committing each transaction when
    379379    a database modifying operation occurs.
     380
     381Transaction management outside the web server
     382=============================================
     383
     384Django's typical transaction and connection management does not work outside
     385the web server context.
     386
     387You may, for example, setup Django to run some recurring tasks in their own
     388threads and notice that they leave behind unfinished database connection
     389processes (in PostgreSQL this manifests as the connections being listed as
     390"Idle In Transaction").
     391
     392Looking through the Postgres logs, you may find that the transactions aren't
     393being completed (no ``ROLLBACK``). Switching to manual transaction management
     394and doing the rollback manually will work, but this still leaves the processes
     395as "Idle". Finally, calling ``django.db.connection.close()`` will end these
     396"Idle" processes. What's going on here and how can we fix it?
     397
     398Transactions
     399------------
     400
     401Django's default :ref:`autocommit behavior<topics-db-transactions-autocommit>`
     402holds true for threaded functions. However, as noted above:
     403
     404    As soon as you perform an action that needs to write to the database,
     405    Django produces the ``INSERT/UPDATE/DELETE`` statements and then does the
     406    ``COMMIT``. There’s no implicit ``ROLLBACK``.
     407
     408That last sentence is very literal. Django DOES NOT issue a ``ROLLBACK``
     409command unless something in Django has set the dirty flag. If your functions
     410are only performing ``SELECT`` statements, it won't set the dirty flag to
     411trigger a ``COMMIT``.
     412
     413This goes against the fact that PostgreSQL thinks the transaction requires a
     414``ROLLBACK`` because Django issued a ``SET`` command for the timezone.
     415
     416Connections
     417-----------
     418
     419Connection management is where things get tricky. Django uses
     420:data:`~django.core.signals.request_finished` to close the database connection
     421it normally uses. Since nothing normally happens in Django that doesn't involve
     422a request, you take this behavior for granted.
     423
     424In this case, though, there isn't a request because the thread is outside the
     425web server process. No request means no signal. No signal means the database
     426connection won't be closed.
     427
     428Going back to transactions, it turns out that simply issuing a call to
     429``django.db.connection.close()`` in the absence of any changes to the
     430transaction management also issues the meeded ``ROLLBACK`` statement.
     431
     432Solution
     433--------
     434
     435The solution is to allow Django's transaction management to proceed as usual
     436and to simply close the connection one of three ways:
     437
     4381. Write a decorator that closes the connection and wrap the necessary
     439   functions in it.
     4402. Hook into the existing :mod:`request signals<django.core.signals>` to
     441   have Django close the connection.
     4423. Close the connection manually (``django.db.connection.close()``) at the end
     443   of the function.
Back to Top