From f94c2a0ec2c7392939285df8b5550c079afa439f Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 5 Jul 2026 15:49:03 +0000 Subject: [PATCH 1/2] Raise informative errors for failed Fastly purges A purge of the private docs service started failing with a 404 "Cannot find service" response from the Fastly API, which surfaced as a bare MatchError. Turn non-200 purge responses into an error message that includes the service name, service id, status, and response body. The MatchError also exposed a bug in Queue.run_in_task/1: task exit reasons like {:badmatch, value} are not exceptions, so passing them to reraise/2 raised ArgumentError and masked the original error. Only reraise when the exit reason is an exception, otherwise exit with the original reason. --- lib/hexdocs/cdn/fastly.ex | 17 ++++++++++++++--- lib/hexdocs/queue.ex | 2 +- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/lib/hexdocs/cdn/fastly.ex b/lib/hexdocs/cdn/fastly.ex index 0a4f72d..08e637f 100644 --- a/lib/hexdocs/cdn/fastly.ex +++ b/lib/hexdocs/cdn/fastly.ex @@ -9,18 +9,29 @@ defmodule Hexdocs.CDN.Fastly do service_id = Application.get_env(:hexdocs, service) sleep_time = div(Application.get_env(:hexdocs, :fastly_purge_wait, @fastly_purge_wait), 2) - {:ok, 200, _, _} = post("service/#{service_id}/purge", body) + purge!(service, service_id, body) Task.Supervisor.start_child(Hexdocs.Tasks, fn -> Process.sleep(sleep_time) - {:ok, 200, _, _} = post("service/#{service_id}/purge", body) + purge!(service, service_id, body) Process.sleep(sleep_time) - {:ok, 200, _, _} = post("service/#{service_id}/purge", body) + purge!(service, service_id, body) end) :ok end + defp purge!(service, service_id, body) do + case post("service/#{service_id}/purge", body) do + {:ok, 200, _headers, _body} -> + :ok + + {:ok, status, _headers, body} -> + raise "failed to purge #{service} (service id: #{service_id}), " <> + "status: #{status}, body: #{inspect(body)}" + end + end + defp auth() do Application.get_env(:hexdocs, :fastly_key) end diff --git a/lib/hexdocs/queue.ex b/lib/hexdocs/queue.ex index 196c1cc..60c47ca 100644 --- a/lib/hexdocs/queue.ex +++ b/lib/hexdocs/queue.ex @@ -401,7 +401,7 @@ defmodule Hexdocs.Queue do case Task.yield(task, :timer.seconds(270)) || Task.shutdown(task) do {:ok, result} -> result - {:exit, {exception, stacktrace}} -> reraise(exception, stacktrace) + {:exit, {exception, stacktrace}} when is_exception(exception) -> reraise(exception, stacktrace) {:exit, reason} -> exit(reason) nil -> raise "task timeout" end From baea17b5fb787999da002c9d64ee39423f4e17c2 Mon Sep 17 00:00:00 2001 From: Claude Date: Sun, 5 Jul 2026 21:07:19 +0000 Subject: [PATCH 2/2] Format queue.ex --- lib/hexdocs/queue.ex | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/lib/hexdocs/queue.ex b/lib/hexdocs/queue.ex index 60c47ca..fafa24e 100644 --- a/lib/hexdocs/queue.ex +++ b/lib/hexdocs/queue.ex @@ -400,10 +400,17 @@ defmodule Hexdocs.Queue do task = Task.Supervisor.async(Hexdocs.Tasks, fun) case Task.yield(task, :timer.seconds(270)) || Task.shutdown(task) do - {:ok, result} -> result - {:exit, {exception, stacktrace}} when is_exception(exception) -> reraise(exception, stacktrace) - {:exit, reason} -> exit(reason) - nil -> raise "task timeout" + {:ok, result} -> + result + + {:exit, {exception, stacktrace}} when is_exception(exception) -> + reraise(exception, stacktrace) + + {:exit, reason} -> + exit(reason) + + nil -> + raise "task timeout" end end