Update documentation for ML-21, ML-9, and Erlang 28.5

- architecture.md: document new ErrorResponse behaviour, HttpError, and
  Worker.ErrorHandler modules plus per-API ErrorResponse pattern
- project-conventions.md: capture API-failure → Oban tuple convention and
  mix_audit CI/pre-commit run
- production-infrastructure.md: bump builder image Erlang to 28.5 and
  note mix_audit in the lint step
This commit is contained in:
Claudio Ortolina
2026-04-24 14:29:35 +01:00
parent 4418fbc377
commit ed2e91400c
3 changed files with 15 additions and 2 deletions
+11
View File
@@ -136,6 +136,9 @@ Last.fm schemas (separate, not Ecto-persisted to main DB):
| `ErrorTracker.ErrorNotifier` | GenServer: attaches to ErrorTracker telemetry, skips muted errors, throttles repeated errors, dispatches email notifications |
| `ErrorTracker.ErrorNotifier.Email` | Builds and sends Swoosh error notification emails with stack trace formatting |
| `ErrorIgnorer` | ErrorTracker.Ignorer implementation: filters non-actionable errors (e.g., NoRouteError from bot scanners) |
| `MusicLibrary.ErrorResponse` | Behaviour for structured API error responses (`retryable?/1`, `retry_delay_seconds/1`) — per-API `ErrorResponse` modules implement this |
| `MusicLibrary.HttpError` | Default HTTP status → kind mapping (`:rate_limit`, `:server_error`, `:timeout`, `:auth_error`, `:not_found`, `:client_error`, `:unknown`) used as baseline by per-API `ErrorResponse` modules |
| `MusicLibrary.Worker.ErrorHandler` | Translates per-API `ErrorResponse` structs into Oban tuples — `{:snooze, seconds}` for retryable, `{:cancel, reason}` for permanent |
| `MusicLibraryWeb.RecordsOnThisDayEmail` | Builds and sends daily "records on this day" email with cover images, anniversary styling |
| `MusicLibrary.Mailer` | Swoosh mailer (Mailgun in prod, local adapter in dev) |
| `FormatNumber` | Number formatting utility |
@@ -159,6 +162,14 @@ Each has a `Config` module reading from application env. All HTTP clients use `R
per-API rate limiting (`Req.RateLimiter`, ETS-backed). In tests, all HTTP calls are
stubbed via `Req.Test` (configured in `config/test.exs`).
Each API also has an `API.ErrorResponse` module (e.g. `MusicBrainz.API.ErrorResponse`,
`OpenAI.API.ErrorResponse`) implementing the `MusicLibrary.ErrorResponse` behaviour,
so workers can uniformly classify HTTP failures as transient (snooze) or permanent
(cancel) via `MusicLibrary.Worker.ErrorHandler`. Per-API overrides capture
API-specific quirks — e.g. MusicBrainz uses HTTP 503 as the rate-limit signal, and
OpenAI splits HTTP 429 into `:rate_limit` vs `:auth_error` by reading the body
`code` (`insufficient_quota` → permanent).
---
## Oban Workers (lib/music_library/worker/)