fix: retry firmware fetch with exponential backoff on network errors

Increase max_attempts from 3 to 10 and add custom backoff/1 that uses
quadratic growth (attempt² × 60s) capped at 2 hours, so transient
network failures retry over ~9 hours rather than being discarded after
3 quick attempts.
This commit is contained in:
Graham McIntire 2026-02-18 10:34:36 -06:00
parent cc26b05a9b
commit f0fea0dd3e
No known key found for this signature in database
2 changed files with 26 additions and 1 deletions

View file

@ -5,7 +5,7 @@ defmodule Towerops.Workers.FirmwareVersionFetcherWorker do
Runs daily to check for new firmware releases and updates the firmware_releases table.
"""
use Oban.Worker, queue: :maintenance, max_attempts: 3
use Oban.Worker, queue: :maintenance, max_attempts: 10
import SweetXml
@ -13,6 +13,11 @@ defmodule Towerops.Workers.FirmwareVersionFetcherWorker do
require Logger
@impl Oban.Worker
def backoff(%Oban.Job{attempt: attempt}) do
min(attempt * attempt * 60, 7_200)
end
@rss_url "https://cdn.mikrotik.com/routeros/latest-stable.rss"
@changelog_url "https://mikrotik.com/download/changelogs"

View file

@ -20,6 +20,26 @@ defmodule Towerops.Workers.FirmwareVersionFetcherWorkerTest do
end
end
describe "backoff/1" do
test "early attempts have shorter delays than later attempts" do
attempt_1 = FirmwareVersionFetcherWorker.backoff(%Oban.Job{attempt: 1})
attempt_5 = FirmwareVersionFetcherWorker.backoff(%Oban.Job{attempt: 5})
assert attempt_1 < attempt_5
end
test "backoff is capped at 2 hours" do
high_attempt = FirmwareVersionFetcherWorker.backoff(%Oban.Job{attempt: 100})
assert high_attempt <= 7_200
end
test "all attempts return positive values" do
for attempt <- 1..10 do
backoff = FirmwareVersionFetcherWorker.backoff(%Oban.Job{attempt: attempt})
assert backoff > 0, "attempt #{attempt} returned non-positive backoff"
end
end
end
describe "parse_rss_feed/1" do
test "parses valid RSS feed XML" do
valid_rss = """