From 85dd8214005ee916bdfadae8a0bf7331d351e6a2 Mon Sep 17 00:00:00 2001 From: Graham McIntire Date: Fri, 24 Apr 2026 10:04:52 -0500 Subject: [PATCH] tests: disable Req retries in test env to eliminate ~7s-per-test delays MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Req's default `retry: :safe_transient` waits ~7s across exponential backoff when the stubbed response is a 5xx or connection error. Tests that asserted error-status behavior paid that price on every run. Disable retries in test env for every direct Req caller: * `Towerops.HTTP` (covers weather/netbox/geocoding/http_executor/pagerduty) * `CnMaestro.Client`, `Gaiia.Client`, `Preseem.Client`, `Sonar.Client`, `Splynx.Client`, `Agents.ReleaseChecker`, `Billing.StripeClient` Use `Keyword.put_new(:retry, false)` so any test explicitly opting into retry behavior is respected. Suite time: 82.8s → 65.3s. Slowest test dropped from 7050ms to 1447ms. --- lib/towerops/agents/release_checker.ex | 4 +++- lib/towerops/billing/stripe_client.ex | 8 ++++++-- lib/towerops/cn_maestro/client.ex | 9 ++++++++- lib/towerops/gaiia/client.ex | 4 +++- lib/towerops/http.ex | 13 ++++++++++++- lib/towerops/preseem/client.ex | 7 +++++-- lib/towerops/sonar/client.ex | 6 +++++- lib/towerops/splynx/client.ex | 8 ++++++-- 8 files changed, 48 insertions(+), 11 deletions(-) diff --git a/lib/towerops/agents/release_checker.ex b/lib/towerops/agents/release_checker.ex index 47fa8663..c840ffd5 100644 --- a/lib/towerops/agents/release_checker.ex +++ b/lib/towerops/agents/release_checker.ex @@ -133,7 +133,9 @@ defmodule Towerops.Agents.ReleaseChecker do defp req_get(url, opts) do opts = if Application.get_env(:towerops, :env) == :test do - Keyword.put(opts, :plug, {Req.Test, __MODULE__}) + opts + |> Keyword.put(:plug, {Req.Test, __MODULE__}) + |> Keyword.put_new(:retry, false) else opts end diff --git a/lib/towerops/billing/stripe_client.ex b/lib/towerops/billing/stripe_client.ex index a8c50d01..0365df30 100644 --- a/lib/towerops/billing/stripe_client.ex +++ b/lib/towerops/billing/stripe_client.ex @@ -216,10 +216,14 @@ defmodule Towerops.Billing.StripeClient do decode_json: [keys: :strings] ] ++ opts - # Use Req.Test in test environment (following existing pattern) + # Use Req.Test in test environment (following existing pattern). + # Also disable retries in test so stubbed 5xx/429 responses return + # immediately instead of spending seconds retrying. req_opts = if Application.get_env(:towerops, :env) == :test do - Keyword.put(req_opts, :plug, {Req.Test, __MODULE__}) + req_opts + |> Keyword.put(:plug, {Req.Test, __MODULE__}) + |> Keyword.put_new(:retry, false) else req_opts end diff --git a/lib/towerops/cn_maestro/client.ex b/lib/towerops/cn_maestro/client.ex index 8e94f517..2c8a596b 100644 --- a/lib/towerops/cn_maestro/client.ex +++ b/lib/towerops/cn_maestro/client.ex @@ -165,8 +165,15 @@ defmodule Towerops.CnMaestro.Client do e -> {:error, Exception.message(e)} end - defp maybe_add_test_plug(opts), do: maybe_attach_test_plug(opts, Application.get_env(:towerops, :env)) + defp maybe_add_test_plug(opts) do + opts + |> maybe_attach_test_plug(Application.get_env(:towerops, :env)) + |> maybe_disable_retry(Application.get_env(:towerops, :env)) + end defp maybe_attach_test_plug(opts, :test), do: Keyword.put(opts, :plug, {Req.Test, __MODULE__}) defp maybe_attach_test_plug(opts, _env), do: opts + + defp maybe_disable_retry(opts, :test), do: Keyword.put_new(opts, :retry, false) + defp maybe_disable_retry(opts, _env), do: opts end diff --git a/lib/towerops/gaiia/client.ex b/lib/towerops/gaiia/client.ex index a7c8d132..b8f30e39 100644 --- a/lib/towerops/gaiia/client.ex +++ b/lib/towerops/gaiia/client.ex @@ -318,7 +318,9 @@ defmodule Towerops.Gaiia.Client do req_opts = if Application.get_env(:towerops, :env) == :test do - Keyword.put(req_opts, :plug, {Req.Test, __MODULE__}) + req_opts + |> Keyword.put(:plug, {Req.Test, __MODULE__}) + |> Keyword.put_new(:retry, false) else req_opts end diff --git a/lib/towerops/http.ex b/lib/towerops/http.ex index 0230da42..6305b9c0 100644 --- a/lib/towerops/http.ex +++ b/lib/towerops/http.ex @@ -4,7 +4,7 @@ defmodule Towerops.HTTP do def request(owner, req_opts) when is_list(req_opts) do req_opts |> maybe_attach_test_plug(owner) - # |> maybe_disable_retry() # Temporarily disabled to debug PagerDuty tests + |> maybe_disable_retry() |> Req.request() rescue error in RuntimeError -> @@ -42,4 +42,15 @@ defmodule Towerops.HTTP do req_opts end end + + # In test, disable Req's default retry-on-5xx/transient-error behavior. + # Without this, tests that stub an error status wait ~7s for retries to + # exhaust before the response is returned. + defp maybe_disable_retry(req_opts) do + if Application.get_env(:towerops, :env) == :test and !Keyword.has_key?(req_opts, :retry) do + Keyword.put(req_opts, :retry, false) + else + req_opts + end + end end diff --git a/lib/towerops/preseem/client.ex b/lib/towerops/preseem/client.ex index 6d19128c..e32e10d2 100644 --- a/lib/towerops/preseem/client.ex +++ b/lib/towerops/preseem/client.ex @@ -116,10 +116,13 @@ defmodule Towerops.Preseem.Client do headers: [{"accept", "application/json"}] ] - # Only use Req.Test plug in test environment + # Only use Req.Test plug in test environment; disable retry in tests + # so stubbed error statuses don't trigger a ~7s exponential backoff. opts = if Application.get_env(:towerops, :env) == :test do - Keyword.put(opts, :plug, {Req.Test, __MODULE__}) + opts + |> Keyword.put(:plug, {Req.Test, __MODULE__}) + |> Keyword.put_new(:retry, false) else opts end diff --git a/lib/towerops/sonar/client.ex b/lib/towerops/sonar/client.ex index 08e2b39b..0f113d63 100644 --- a/lib/towerops/sonar/client.ex +++ b/lib/towerops/sonar/client.ex @@ -159,7 +159,11 @@ defmodule Towerops.Sonar.Client do {:error, Exception.message(exception)} end - defp maybe_attach_test_plug(req_opts, :test), do: Keyword.put(req_opts, :plug, {Req.Test, __MODULE__}) + defp maybe_attach_test_plug(req_opts, :test) do + req_opts + |> Keyword.put(:plug, {Req.Test, __MODULE__}) + |> Keyword.put_new(:retry, false) + end defp maybe_attach_test_plug(req_opts, _env), do: req_opts diff --git a/lib/towerops/splynx/client.ex b/lib/towerops/splynx/client.ex index 685b8b1d..a9b2ee6c 100644 --- a/lib/towerops/splynx/client.ex +++ b/lib/towerops/splynx/client.ex @@ -76,7 +76,9 @@ defmodule Towerops.Splynx.Client do req_opts = if Application.get_env(:towerops, :env) == :test do - Keyword.put(req_opts, :plug, {Req.Test, __MODULE__}) + req_opts + |> Keyword.put(:plug, {Req.Test, __MODULE__}) + |> Keyword.put_new(:retry, false) else req_opts end @@ -119,7 +121,9 @@ defmodule Towerops.Splynx.Client do req_opts = if Application.get_env(:towerops, :env) == :test do - Keyword.put(req_opts, :plug, {Req.Test, __MODULE__}) + req_opts + |> Keyword.put(:plug, {Req.Test, __MODULE__}) + |> Keyword.put_new(:retry, false) else req_opts end