From 61e30f7cfa15cf5d9a175c1ca74ab967eb662363 Mon Sep 17 00:00:00 2001 From: Parker Selbert Date: Thu, 4 Jan 2024 11:11:45 +0000 Subject: [PATCH] Handle rollback during postgres peer election MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Infrequently, the postgres peer election transaction returns `{:error, :rollback}`. Now that return value is handled to prevent a match error. The peer maintains its current `leader?` status on rollback—this may cause inconsistency if the leader encounters an error and multiple rollbacks happen in sequence. That tradeoff is acceptable because the situation is unlikely and less of an issue than crashing the peer. Closes #1007 --- lib/oban/peers/postgres.ex | 25 +++++++++++++++++-------- 1 file changed, 17 insertions(+), 8 deletions(-) diff --git a/lib/oban/peers/postgres.ex b/lib/oban/peers/postgres.ex index b0c2829d..67f6855d 100644 --- a/lib/oban/peers/postgres.ex +++ b/lib/oban/peers/postgres.ex @@ -90,14 +90,23 @@ defmodule Oban.Peers.Postgres do state = :telemetry.span([:oban, :peer, :election], meta, fn -> - {:ok, state} = - Repo.transaction(state.conf, fn -> - state - |> delete_expired_peers() - |> upsert_peer() - end) - - {state, %{meta | leader: state.leader?}} + fun = fn -> + state + |> delete_expired_peers() + |> upsert_peer() + end + + case Repo.transaction(state.conf, fun) do + {:ok, state} -> + {state, %{meta | leader: state.leader?}} + + {:error, :rollback} -> + # The peer maintains its current `leader?` status on rollback—this may cause + # inconsistency if the leader encounters an error and multiple rollbacks happen in + # sequence. That tradeoff is acceptable because the situation is unlikely and less of + # an issue than crashing the peer. + {state, meta} + end end) {:noreply, schedule_election(state)}