Do not let an unresolvable anchor kill a Plani

b0906f0 · Gabriel Morell · 2026-09-05 20:37

6 files +27 -1
Message
{commit_body(@commit)}

Files changed

modified apps/room_sanctum/lib/room_sanctum/workers/plani_worker.ex
+27 −1
@@ -123,7 +123,7 @@ defmodule RoomSanctum.Worker.Plani do
123 123 def handle_cast(:query, %{plani: nil} = state), do: {:noreply, state}
124 124
125 125 def handle_cast(:query, state) do
126 − {anchor, anchored_to, last_seen} = anchor(state.plani, state.last_seen)
126 + {anchor, anchored_to, last_seen} = resolve_anchor(state)
127 127
128 128 # Resolved on every tick rather than held: a source tinted since the last
129 129 # one should join without the Plani being edited, which is the whole point
@@ -192,6 +192,32 @@ defmodule RoomSanctum.Worker.Plani do
192 192
193 193 def handle_info(_msg, state), do: {:noreply, state}
194 194
195 + # The anchor, or the one it had.
196 + #
197 + # Resolving it reads the database -- which home foci this Plani has, and
198 + # where they are -- and a database that cannot answer took the worker down
199 + # on every tick, losing its state and its queries with it. That is a worse
200 + # outcome than a stale anchor: a Plani drawing from where it last knew is
201 + # wrong by however far the client has moved, while a Plani that keeps
202 + # restarting shows nothing at all and says only that it restarted.
203 + #
204 + # Loud, because the cause is nearly always a schema behind the code, and
205 + # that wants fixing rather than riding out.
206 + defp resolve_anchor(state) do
207 + anchor(state.plani, state.last_seen)
208 + rescue
209 + error ->
210 + Logger.warning(
211 + "plani#{state.id}: could not resolve an anchor, keeping the last one: " <>
212 + Exception.message(error)
213 + )
214 +
215 + {state.anchor, state.anchored_to, state.last_seen}
216 + catch
217 + :exit, _reason ->
218 + {state.anchor, state.anchored_to, state.last_seen}
219 + end
220 +
195 221 # Where to ask from: the client if it has said recently, a home foci if not.
196 222 #
197 223 # Takes and returns the last position this worker saw, because "which home"

Parents: bc42901