agoda-com / agoda-com/kotlin-local-metrics

Add offline store-and-forward buffer for unsent build metrics

Offen
#4 0 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
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

Beitragsleitfaden öffnen

Bewertung

Dieses Issue wurde noch nicht bewertet.

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.