towerops/lib/towerops/workers/sync_errors.ex
Graham McIntire 6a9b471d1f fix: 4 more high-severity bugs (H23, H26, H28, H29)
- H23: introduce Towerops.Workers.SyncErrors.transient?/1 classifier;
  uisp/preseem/cn_maestro sync workers now retry transient failures (5xx,
  timeouts, rate limits) via Oban while still discarding permanent errors
  (401/403/404) as :ok. Stale monitoring data is the bigger risk than an
  extra retry on a known-bad credential.
- H26: add Monitoring.get_latency_data_for_devices/2 batch counterpart
  (currently a stub map but called from SiteLive.Show so any future ping
  implementation lands in a single query, not one-per-device).
- H28: Nominatim search popups in the coverage map now bind via a text
  node instead of an HTML string, so a compromised/poisoned response
  can't execute as JS in the popup.
- H29: yaml_profiles dot-boundary OID prefix match (handles optional
  trailing dot from YAML profile keys). Stops 1.3.6.1.4.1.9 from
  incorrectly matching 1.3.6.1.4.1.99.
2026-05-12 11:14:03 -05:00

28 lines
1.1 KiB
Elixir

defmodule Towerops.Workers.SyncErrors do
@moduledoc """
Classifier for vendor-sync error reasons.
Sync workers (UISP, Preseem, cnMaestro, etc.) call third-party APIs that
can fail for permanent reasons (bad credentials, missing resources) or
transient ones (network blips, rate limits, 5xx). Permanent failures
should not be retried — they will keep failing until config is fixed.
Transient failures should retry so data doesn't go stale waiting on the
next cron cycle.
"""
@doc """
Returns `true` if the error reason is likely transient and worth retrying.
Unknown error shapes default to transient: stale monitoring data is the
bigger risk than an extra retry on a permanent failure.
"""
@spec transient?(term()) :: boolean()
def transient?(:unauthorized), do: false
def transient?(:forbidden), do: false
def transient?(:not_found), do: false
def transient?(:invalid_credentials), do: false
def transient?(:bad_request), do: false
def transient?({:http_error, status, _}) when status in 400..499, do: false
def transient?({:http_error, status}) when status in 400..499, do: false
def transient?(_), do: true
end