-
Notifications
You must be signed in to change notification settings - Fork 55
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
run_transaction backwards compatibility #43
Comments
@xarg it would be nice to be able to do that, but not handling conflicts is not an option as the resulting database would not behave in a well-defined way (by any way of defining this). Similarly, just "not carrying out" the operation is similarly problematic. Please let us know if that's not what you had in mind. Note that as an (inferior) workaround, you can also just run the transaction invocation in a loop as long as it returns the respective failure. The latter is roughly what existing apps "should" already do if they use Postgres on SERIALIZABLE mode (I realize that conflicts are rarer there, so that few real-world apps handle them). |
Thanks for clarifying @tschottdorf I believe I understand a bit better why this is not a good idea for CRDB especially after reading this article: https://www.cockroachlabs.com/docs/stable/transactions.html#transaction-retries Wouldn't running transaction in a loop lead to a similar behavior as the I was also wondering why the Instead of:
This:
Is there a particular reason to use callbacks? |
Closing this for now. There is a better context manager discussion here: #25 |
@xarg #25 is indeed a better issue to discuss the session, thanks! The problem with
is that the "undirected retry" (i.e. the loop) will create a new transaction in each iteration, which is less effective when conflicts do occur. For example, it can make it more likely that transactions are starved (i.e. have to restart repeatedly, without getting closer to committing). |
#25 isn't really about using context managers, even though some of the discussion uses that syntax. It's about whether the The reason it's not a context manager is that context managers cannot perform retries: they execute their bodies zero or one times. There's nothing in python that combines reusable code objects with exception handling. You need either a
There are some things about this syntax that I like (everything's "in order" and I don't need to name a function), and some things I don't (this is a very unusual pattern and there's no "function signature" to guide you into it, and there's an extra horizontal indent). |
Since you can reuse the same session even if the transaction has failed I came up with this code (look at
This is how I use it:
|
This won't work: |
Thanks @bdarnell I see what you mean. Sorry if it's too basic of a question: but why can't the retry be implemented on the session level? Was it tried and SA does not allow it or not? What I mean by session level is having something like:
|
On the second try, Note that if you use the query builder interface (or raw sql) instead of the ORM, you may be able to construct a single SQL statement that does what you want. If so, the cockroach server can take care of all the retries for you and you shouldn't see serialization failures being raised to the application. |
Thanks again for your response (and for having the patience with me). I still don't understand it well so let me try to illustrate this another way. Suppose I have 2 async workers (worker A and B). They both try to update the same row (a user full name).
Now A and B get there, select the user row and now A is first to update the name and to a In PG If I understood anything from our discussion in CRDB the above would raise a conflict and allow the app to retry the same transaction (optionally) checking that I'm not overwriting anything. I'm also guessing that this exacerbated by CRDB because it needs to sync between nodes so it could be that it's not really a different client doing work on that row but a CRDB node - so the conflict is more likely. While I think that is the 'correct' way to do it (probably for any db) - it's verbose and I wonder why not use the Automatic Retries by default and also allow the developer to decide where to use the retry logic. Does that make sense? |
This is a question of transaction isolation levels. Postgres defaults to The retry loop is not technically cockroach-specific: If you changed the isolation level to
We can only do automatic retries when we can see the entire transaction in the SQL (this generally requires constructing the queries by hand instead of using an ORM). We can't retry if the transaction is a combination of SQL and logic in your application code. Note that you may not need to modify the way you run transactions if your application handles retries at another level. For example, in an offline-first mobile app you probably do all your writes asynchronously from the user's perspective and can tolerate network outages, so it doesn't matter if the server-side request returns an error when there is a transaction conflict. |
How about detecting when someone uses nested transactions and disabling auto-retries? Or allowing the user to disable auto-retries and in that case supporting nested transactions? |
Unfortunately it doesn't work in that order. The retry protocol requires a SAVEPOINT statement to be issued before we know what the application code is going to do.
You don't have to use |
Oh, so one level of |
No, |
Then Flask-SQLAlchemy is already using that one level in it's request session, so I can't use transactions. I'm on v2.0-beta.20180319 without using |
Retryable errors mainly occur in the presence of concurrent transactions that interfere with each other. |
I understand the motivation behind the conflict handling and the need to use a callback, but in existing projects this is going to take a lot of work before being able to switch from PG to CRDB.
Are there any plans to add a backwards compatibility mode where the conflicts are not treated, but instead a warning is raised? This way the migrations from PG to CRDB could be done progressively.
The text was updated successfully, but these errors were encountered: