nhpip
DB(dis)Connection - ERROR: could not serialize access due to concurrent update
Hi,
We are using DBConnection and Ecto with a Postgres DB. Occasionally we get errors like below in the Postgres log:
2022-09-17 12:36:59.478 EDT [92184] ERROR: could not serialize access due to concurrent update
2022-09-17 12:36:59.478 EDT [92184] CONTEXT: SQL statement "update collections
set scoped_seq = scoped_seq + 1
where id = collection_id
returning scoped_seq"
PL/pgSQL function advance_seq(uuid) line 5 at SQL statement
SQL statement "select advance_seq(new.collection_id)"
PL/pgSQL function set_rev_id() line 3 at SQL statement
90% of the time this results in a Postgrex.Error exception with a code of :serialization_failure which permits us to retry the transaction.
However, in a small percentage of cases we get the same error in the Postgres log, but instead a DBConnection.ConnectionError exception with a message of:
12:17:13.217 [error] Postgrex.Protocol (#PID<0.2447.0>) disconnected: ** (DBConnection.ConnectionError) transaction rolling back
My questions are:
- Why do we sometimes get a Postgrex error and sometimes a DBConnection disconnect for what appears to be the same error?
- Why should it disconnect?
- Can we stop it from disconnecting (or force a reconnect)?
Now I can retry the transaction further up the stack, but that involves re-doing lots of data processing and doesn’t always work.
We are running latest of db_connection, ecto and postgrex.
Thanks
Marked As Solved
joey_the_snake
In general Postgrex.Error means your query went through to the database and the response from the database was an error. DBConnection.Error there wasn’t a clean send/receive to/from the db.
In your case it looks like that error comes when you try to execute a query on a transaction that is already rolling back. So this puts the connection in an erroneous state and it raises/disconnects.
A wild guess: you are retrying in the same transaction you receive the error in instead of letting the transaction completely roll back and starting a new one.
Also Liked
nhpip
Thanks, that makes total sense. It was before my time, but the implementation is kind of weird. The pseudo code looks like:
defmodule Server do
def transaction(mod, fun, args, .....) do
try do
Repo.transaction(fn ->
....
case apply(mod, fun, args) do
{:ok, rsp} -> rsp
{:error, e} -> Repo.rollback(e)
end)
rescue
e in Postgrex.Error ->
repeat_logic_if_serializatiion_error(...)
end
end
end
Now the problem is that mod, fun can also invoke Server.transaction, with a different mod, fun. Indeed it can get quite deep. So it’s possible that the exception can get caught and repeated in an inner layer.
Thanks again…
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #advent-of-code
- #elixirconf-us
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #performance








