I’m working on debugging a TransactionRetryWithProtoRefreshError
error that comes up from time to time on an app using CockroachDB. The errors get logged as something like the following (truncated)
ERROR 40001 (serialization_failure) restart transaction: TransactionRetryWithProtoRefreshError: TransactionRetryError: retry txn (RETRY_SERIALIZABLE - failed preemptive refresh due to a conflict: committed value on key ...
One of the suggestions for dealing with this error is to have the database client retry the operation. Is there a way to make Ecto
retry a query?
Another possible way to deal with this error is to modify the query so we can flag the selected data so Cockroach knows it’s gonna get used as part of an update. Cockroach offers this FOR UPDATE
syntax, which translates to queries that look something like this:
SELECT * FROM foo
WHERE bar ='x' ORDER BY updated_at
FOR UPDATE;
Previously, I had used the Ecto
:hints
option to pass other Cockroach-specific options like AS OF SYSTEM TIME
to queries by modifying the Repo
’s prepare_query/3
function to something like this:
def prepare_query(_operation, %{from: %{hints: []}} = query, opts) do
case Keyword.get(opts, :hints, []) do
[] -> {query, opts}
hints -> {put_in(query.from.hints, hints), opts}
end
end
That worked pretty well so we could do things like the following:
Repo.all(MySchema, hints: ["AS OF SYSTEM TIME '-5m'"])
See related thread
.
However, this doesn’t work when the query includes where
clauses. In the logs, I can see that the query isn’t being built in a way that Cockroach needs. The query that gets built is something like this:
SELECT c0."foo", c0."bar", ...
FROM "my"."table" AS c0 FOR UPDATE WHERE (c0."foo" = $1)
but the FOR UPDATE
bit needs to be at the end, e.g.
SELECT c0."foo", c0."bar", ...
FROM "my"."table" AS c0 WHERE (c0."foo" = $1) FOR UPDATE
Granted, this is probably what I get for trying to leverage the :hints
option for things that it really wasn’t intended for. Is there any way to modify the existing queries outside of writing raw SQL?
Relevant CockroachDB docs: