On Thu, 23 Jun 2011 03:59:49 +0200, Zygmunt Krynicki zygmunt.krynicki@linaro.org wrote:
W dniu 22.06.2011 00:21, Michael Hudson-Doyle pisze:
Fortunately django almost never runs in autocommit mode. There is an implicit transaction around the whole request. It is easy to control the transaction processing around a piece of code, see [1].
I got very confused by this, I admit. In general, calling .save() on a model does a COMMIT, unless you're managing the transactions yourself (or using TransactionMiddleware)?
Something like that.
It's easier to read the source than read my explanations. django.db.models.base:Model.base_save() calls transaction.commit_unless_managed().
OK.
In practice, django is almost always managed so save is never commits.
Really? TransactionMiddleware isn't installed by the settings file that django-admin startapp creates. Is this just a crummy default that everyone changes?
The transaction middleware you mentioned makes django views "managed" using commit_on_success decorator on the request method. You need to disable that manually and I don't see any reason why someone would such a thing.
See above.
And of course, the way this is being done in the scheduler at the moment is not part of the web app, so the "usual" stuff doesn't always apply.
On PostgreSQL we also need to properly implement handling of IngegrityError as it differs significantly from SQLite [2]
It's just that it dooms transactions, right?
Not really, it just makes supporting them a little trickier. I do that with deserialization of bundles. In practice it's quite easy if you remember to use save points correctly. See my 1-4 points below for explanation why.
The approach we'll take on
integrity errors is to rollback and retry so that's easy.
You can rollback to a savepoint.
Yeah, but there's no reason to do that in getJobForBoard.
(it's confusing that https://docs.djangoproject.com/en/dev/topics/db/transactions/#transaction-ro... says that the changes made by a.save() will be lost when the default is for .save() to commit, so they must be assuming that you're using TransactionMiddleware).
It's not only transaction middleware. Any code that earlier (in the call history of a particular function) enabled transactions will behave this way.
Sure, but it's a bit disingenuous to not mention that in the documentation I think. I guess I should file a ticket.
In reality this is all manageable:
- Proper code will work regardless autocommit mode :-)
- PostgreSQL does not break things, you just need to take account for
savepoints. 3) Handling transactions manually implies you use savepoints and thus get 1 and 2 right.
s/savepoints/savepoints or transactions/ -- there's no requirement to involve savepoints if you don't need to.
- Handling transactions automatically (around a view) implies you get
shielded from most of the complexity, if your actual application logic is happy not to use explicit manual transactions in such cases.
Yeah, it's very good default for webapps. Launchpad does that, but goes even further: it automatically does a rollback when a GET method completes, and uses SERIALIZABLE isolation level, retrying a method if the commit fails due to a serialization violation.
However the code I'm working on is not part of a webapp :)
https://code.launchpad.net/~mwhudson/lava-scheduler/daemon-v1/+merge/65616 btw.
Cheers, mwh