agoda-com / agoda-com/kotlin-local-metrics
Add offline store-and-forward buffer for unsent build metrics
- Vorherrschende Sprache
- Kotlin
- Sterne
- 0
- Forks
- 0
- PR-Merge-Kennzahlen
- Keine gemergten PRs in 30 T.
Beschreibung
## 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.
Beitragsleitfaden
Bewertung
Dieses Issue wurde noch nicht bewertet.