agoda-com / agoda-com/kotlin-local-metrics
Add offline store-and-forward buffer for unsent build metrics
- Lingua principale
- Kotlin
- Stelle
- 0
- Fork
- 0
- Metriche di merge delle PR
- Nessuna PR unita negli ultimi 30g
Descrizione
## Summary
Add an offline "store-and-forward" buffer so build metrics that fail to send (e.g. the developer is offline or the metrics endpoint is unreachable) are persisted locally and retried on a later successful build, instead of being silently dropped.
## Motivation
`MetricsPublisher` currently posts fire-and-forget: the request is sent asynchronously with a short timeout, the response is discarded, and any failure is swallowed. That keeps builds fast and non-blocking, which is good — but it also means a metric is **lost forever** whenever the endpoint is temporarily unreachable (offline, VPN down, DNS failure, endpoint outage).
For developer-local metrics this matters, because the exact times a developer is offline or on a flaky connection are also times we'd still like to capture build/compile data once connectivity returns.
## Proposed behavior
1. When a POST fails due to a connectivity error (e.g. unknown host / connection refused / timeout), write the serialized JSON payload to a local buffer directory instead of discarding it.
2. On the next build where a POST **succeeds**, flush the buffered payloads: attempt to send each one, and delete it on success.
3. Cap the buffer (max number of files and/or max age) so it can't grow unbounded, and drop the oldest entries beyond the cap.
4. Keep it best-effort and non-blocking: all buffer I/O and flushing should never fail the build or add noticeable latency.
### Suggested location for the buffer
Use a stable per-user location under the Gradle user home (already available to the build service), e.g. a dedicated subdirectory, with one file per payload named by the payload `id`.
## Implementation sketch
- `MetricsPublisher`
- Distinguish a connectivity failure from other outcomes so we know when to buffer vs. flush.
- On successful send, trigger a flush of the buffer.
- `BuildMetricsService`
- Pass the buffer directory (derived from the Gradle user home) through the service `Parameters`.
- Continue to swallow errors and stay off the critical path.
- New small helper (e.g. `UnsentMetricsBuffer`) responsible for `save(id, json)`, `list()`, `delete(...)`, and enforcing the size/age cap. Keep it a plain object/util — no new interfaces or abstractions unless a second implementation actually appears.
## Acceptance criteria
- [ ] A failed send caused by an unreachable endpoint results in the payload being written to the local buffer.
- [ ] A later successful send flushes and removes previously buffered payloads.
- [ ] The buffer is bounded (count and/or age) and never grows unbounded.
- [ ] Buffering and flushing never block or fail the build, and add negligible overhead.
- [ ] Deterministic unit tests cover: buffer on failure, flush + delete on success, and cap enforcement (no time-based retries/flakiness).
## Notes / open questions
- Should flushing happen inline on the next successful send, or on a bounded background attempt at build start? (Leaning toward "on next successful send" to avoid extra network calls when still offline.)
- What are sensible defaults for the cap (e.g. N most-recent payloads, discard older than X days)?
- Payloads are plain build/compile metrics; confirm nothing sensitive is persisted before writing to disk.
Guida per i contributori
Apri la guida per i contributori
Direzione di ricerca
Start by reading MetricsPublisher and BuildMetricsService, including how the Gradle user home reaches service Parameters. Define the small UnsentMetricsBuffer around save, list, delete, and cap enforcement, then add deterministic unit tests for buffering on connectivity failure, flush-and-delete after success, and cap enforcement. Done means buffering and flushing remain best-effort without failing or noticeably delaying builds.
Scritto dal modello di indicizzazione a partire dal testo della issue.
Valutazione
- Stack tecnologico
- kotlin
- Ambito
- build-system, developer-experience, observability
- Tipo di issue
- Funzionalità
- Difficoltà
- 4/5
- Tempo stimato
- 3-5 giorni
- Stato di attività
- Tranquilla
- Chiarezza
- Abbastanza chiara
- Idoneità per principianti
- 52/100