Non obvious causes of a transaction conflict?

Anvil"s internal db model makes this harder to reason about than simply whether the same rows are affected or not. What appears to you as separate data tables are actually views on a much smaller set of tables (with inserts, updates and deletes handled by db triggers) .

I can’t stress enough the efficacy of the pragmatic approach over the analytic approach for this type of problem. (I’m an Engineer by background, rather than a Computer Scientist, so no surprise there).

Put some debugging lines in - either print statements or the logging utils from anvil extras - get some hard evidence for what’s going on.

I’ve been surprised to find multiple server calls happening often enough now to just assume it will happen.

1 Like

Anvil’s Data Tables are backed by Postgres, and anvil.table.Transactions are fully SERIALIZABLE. In this mode, Postgres is conservative in identifying conflicts (ie it will sometimes abort an entirely valid transaction), and we’ve found you can get false-positive cross-talk between different apps using the same shared hosting infrastructure. So it’s entirely possible for your app to see transaction rollbacks when nothing else is touching your tables! It’s always a good idea to expect that any transaction might need to retry, and do rapid transactions inside @anvil.tables.in_transaction functions that automatically retry. (We’re working on ways to improve transaction performance and reduce false-positive aborts, but this advice will still apply!)

4 Likes

If we see a transaction conflict come back to the client, and the function in question is using the decorator, does that mean the transaction retried 5 times and had a conflict each time?

You can have a read through the code for the decorator at:

https://github.com/anvil-works/anvil-runtime/blob/master/services/anvil/tables/init.py

1 Like

Based on that I’d have to say that yes, any transaction conflict getting back to the client has happened the maximum number of times (which appears to be 8 rather than 5).

That makes me wonder about an intermittent conflict. If it were truly a false positive, I’d expect that to shake out in one of the retries.

1 Like

Agreed.

In the long run, I should be prepared to switch to the decorator on any of the Transactions in my server code.

Yep. And that suggests that the problem arises from code within the transaction rather than any external event.

That, again, leads to debugging and narrowing of scope as the path to a solution.

1 Like

My mental model of best practices for transactions is becoming:

  1. Do all searches outside of the transaction

  2. Do the updates in a decorated function using the info from #1

That’ll narrow the transaction scope to just updates (multiple updates, no need for a transaction if it’s a single field being updated), and hopefully reduce the chances for false positives.

I’m glad I have a reasonably concurrency friendly app, where each user is only affecting their own data and not collaboratively editing anything. This is more of a best practices exercise for me.

1 Like

This can be trickier than it looks. Nothing in Anvil prevents a user from logging in multiple times, in multiple browser tabs. I know several folks who have so many browser tabs open, they don’t bother going to look for “the one” where they logged in; they just log in again.

And then log in again when they get home, for good measure.

So if you’re counting on a user’s records being accessed from at most one browser session at a time…

1 Like

Definitely something to take into account. There’s nothing in the app that alters any user records without the user taking an action (clicking a button), so it doesn’t matter to me if they’re logged in from multiple sources, as long they’re not actively trying to use both at the same time.

Right. Of course, there are scenarios like this. A busy boss hands out work to several subordinates, all under the same log-in. The subordinates fail to coordinate properly, and so the same data record finds itself being edited from several different browsers at once. Often, only the very last “save” wins.

Given that there is no sure way to know when a browser tab closes, it’s a real headache if you have to guard against this sort of thing.