GitLab: a host it can't reach skips the poll, not the worker

eeea624 · Gabe Morell · 2026-11-05 16:25

7 files +34 -21

Files changed

modified apps/room_gitlab/lib/room_gitlab/gitlab_worker.ex
+23 −21
@@ -172,7 +172,22 @@ defmodule RoomGitlab.Worker do
172 172 defp gitlab_path(:commits, id), do: {"/api/v4/projects/#{id}/repository/commits/master", %{}}
173 173 defp gitlab_path(:jobs, id), do: {"/api/v4/projects/#{id}/jobs", %{}}
174 174
175 − defp do_gitlab_reqa(uri, token, lookup, id \\ nil) do
175 + # Starts a request and files `entry` under its id. One that can't start
176 + # (the host unreachable, say) is logged and left out; the next poll tries
177 + # again.
178 + defp start_req(refs, state, url, pat, {lookup, id}, entry) do
179 + case do_gitlab_reqa(url, pat, lookup, id) do
180 + {:ok, ref} ->
181 + {:ok, fd} = StringIO.open("")
182 + Map.put(refs, ref.id, Map.put(entry, :fd, fd))
183 +
184 + {:error, %HTTPoison.Error{reason: reason}} ->
185 + Logger.warning("GLab::#{state.inst.id} #{lookup} request failed: #{inspect(reason)}")
186 + refs
187 + end
188 + end
189 +
190 + defp do_gitlab_reqa(uri, token, lookup, id) do
176 191 {path, params} = gitlab_path(lookup, id)
177 192
178 193 HTTPoison.get(
@@ -204,10 +219,7 @@ defmodule RoomGitlab.Worker do
204 219
205 220 with true <- state |> Map.get(:inst, %{}) |> Map.get(:enabled),
206 221 {url, pat} when is_binary(url) and is_binary(pat) <- gitlab_creds(state.inst) do
207 − {:ok, ref} = do_gitlab_reqa(url, pat, :projects)
208 − {:ok, fd} = StringIO.open("")
209 − refs = state |> Map.get(:refs)
210 − refs = refs |> Map.put(ref.id, %{fd: fd, type: :projects})
222 + refs = start_req(state.refs, state, url, pat, {:projects, nil}, %{type: :projects})
211 223
212 224 {:noreply, state |> Map.put(:refs, refs)}
213 225 else
@@ -240,17 +252,12 @@ defmodule RoomGitlab.Worker do
240 252 def handle_cast(:query_commits, state) do
241 253 with true <- state |> Map.get(:inst, %{}) |> Map.get(:enabled),
242 254 {url, pat} when is_binary(url) and is_binary(pat) <- gitlab_creds(state.inst) do
243 − all =
244 − state.projects
245 − |> Enum.map(fn p ->
255 + refs =
256 + Enum.reduce(state.projects, state.refs, fn p, acc ->
246 257 Logger.info("GLab::#{state.inst.id} Querying Commits for #{p["name"]}")
247 − {:ok, ref} = do_gitlab_reqa(url, pat, :commits, p["id"])
248 − {:ok, fd} = StringIO.open("")
249 − {ref.id, %{fd: fd, type: :commits, id: p["id"]}}
258 + start_req(acc, state, url, pat, {:commits, p["id"]}, %{type: :commits, id: p["id"]})
250 259 end)
251 − |> Map.new()
252 260
253 − refs = state |> Map.get(:refs) |> Map.merge(all)
254 261 {:noreply, state |> Map.put(:refs, refs)}
255 262 else
256 263 _ -> {:noreply, state}
@@ -268,18 +275,13 @@ defmodule RoomGitlab.Worker do
268 275 "GLab::#{state.inst.id} Querying Jobs for #{length(state.projects)} watched projects"
269 276 )
270 277
271 − all =
272 − state.projects
273 − |> Enum.map(fn p ->
278 + refs =
279 + Enum.reduce(state.projects, state.refs, fn p, acc ->
274 280 id = p["id"]
275 281 Logger.debug("GLab::#{state.inst.id} Querying Jobs for #{id}")
276 − {:ok, ref} = do_gitlab_reqa(url, pat, :jobs, id)
277 − {:ok, fd} = StringIO.open("")
278 − {ref.id, %{fd: fd, type: :jobs, id: id}}
282 + start_req(acc, state, url, pat, {:jobs, id}, %{type: :jobs, id: id})
279 283 end)
280 − |> Map.new()
281 284
282 − refs = state |> Map.get(:refs) |> Map.merge(all)
283 285 {:noreply, state |> Map.put(:refs, refs)}
284 286 else
285 287 _ ->
modified apps/room_gitlab/test/gitlab_worker_test.exs
+11 −0
@@ -84,6 +84,17 @@ defmodule RoomGitlab.WorkerTest do
84 84 end
85 85 end
86 86
87 + test "a GitLab it can't reach skips the poll instead of crashing", %{state: state} do
88 + # A port nothing listens on: the request fails before it starts.
89 + {:ok, sock} = :gen_tcp.listen(0, [])
90 + {:ok, port} = :inet.port(sock)
91 + :ok = :gen_tcp.close(sock)
92 + state = put_in(state.inst.config.url, "http://127.0.0.1:#{port}")
93 +
94 + assert {:noreply, state} = query_jobs(state, [11, 22])
95 + assert state.refs == %{}
96 + end
97 +
87 98 test "what still arrives for a request after its end is dropped", %{state: state} do
88 99 # Its connection, already gone.
89 100 conn = spawn(fn -> :ok end)

Parents: 328b281