Deployment and lifecycle management for Nix
0
fork

Configure Feed

Select the types of activity you want to include in your feed.

fix: add backoff to garden socket reconnection

Use progressive backoff delays (200ms, 500ms, 1s, 2s) when the garden
socket disconnects, instead of immediately retrying. Resets the backoff
counter on successful connection.

sow-142

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+37 -5
+37 -5
apps/garden/lib/garden/socket.ex
··· 95 95 # 96 96 97 97 @impl Slipstream 98 + def handle_connect(socket) do 99 + Logger.info( 100 + msg: "Connected to websocket", 101 + authority: socket.channel_config.uri.authority, 102 + path: socket.channel_config.uri.path 103 + ) 104 + 105 + socket = assign(socket, :reconnect_counter, 0) 106 + {:ok, join(socket, @lobby_topic)} 107 + end 108 + 109 + @impl Slipstream 98 110 def init(_args) do 99 111 case do_connect() do 100 112 {:ok, socket} -> ··· 113 125 @impl Slipstream 114 126 def handle_disconnect(_reason, socket) do 115 127 Logger.warning(msg: "Disconnected from server socket") 128 + {:ok, schedule_reconnect(socket)} 129 + end 116 130 117 - case do_connect(socket) do 118 - {:ok, socket} -> {:ok, socket} 119 - {:error, reason} -> {:stop, reason, socket} 120 - end 131 + defp schedule_reconnect(socket) do 132 + counter = Map.get(socket.assigns, :reconnect_counter, 0) 133 + 134 + backoff_times = 135 + Application.get_env(__MODULE__, :reconnect_after_msec, [200, 500, 1_000, 2_000]) 136 + 137 + delay = Enum.at(backoff_times, counter, List.last(backoff_times)) 138 + 139 + Logger.info(msg: "Scheduling reconnect", delay_ms: delay, attempt: counter + 1) 140 + Process.send_after(self(), :attempt_reconnect, delay) 141 + 142 + assign(socket, :reconnect_counter, counter + 1) 121 143 end 122 144 123 145 defp do_connect(socket \\ nil) do ··· 256 278 nil 257 279 end 258 280 end 259 - 260 281 261 282 defp schedule_reauthentication(socket, %{expires_in: expires_in}) 262 283 when is_integer(expires_in) do ··· 515 536 send(self(), :check_pending_reload) 516 537 517 538 {:noreply, %{socket | active_deployments: active_deployments}} 539 + end 540 + end 541 + 542 + def handle_info(:attempt_reconnect, socket) do 543 + case do_connect(socket) do 544 + {:ok, socket} -> 545 + {:noreply, socket} 546 + 547 + {:error, reason} -> 548 + Logger.warning(msg: "Reconnect attempt failed", error: inspect(reason)) 549 + {:noreply, schedule_reconnect(socket)} 518 550 end 519 551 end 520 552