Preserve and retry telemetry match boundaries across restarts

This commit is contained in:
2026-10-12 12:25:14 -04:00
parent 1121b44857
commit 158916b664
16 changed files with 1603 additions and 142 deletions
+64 -2
View File
@@ -48,7 +48,69 @@ Both plugins now default to a 5-second connection timeout and 15-second total
transfer timeout. Request options can override these with positive millisecond
values. Telemetry explicitly sets those limits and logs native HTTP status and
timings. See the [T5](t5/plugins/README.md) and [T6](t6/plugins/README.md) plugin notes.
Requests are still sent once, in order, with no retries or event timestamp changes.
Telemetry retries and durable replay require the updated plugins; see the
[delivery and rollout notes](#telemetry-delivery-and-rollout-t5-and-t6).
## Telemetry delivery and rollout (T5 and T6)
**Deploy Electric Cherry [#144](https://gitea.thewrightserver.net/josh/electric-cherry/issues/144)
before these reporters.** Replay requires the receiver to associate reports with
`match` and deduplicate `seq`; the legacy receiver can apply an old end to a newer
match. Build and install both updated TWS plugins, restart the server processes,
then deploy the corresponding scripts. The new `telemetryNewMatch`,
`telemetryLoad`, `telemetryStore`, `telemetryRemove` and `telemetryResponse`
functions are required even if telemetry is disabled by dvar.
Every captured report includes a `match` key (random native process token plus
an increasing match counter, at most 64 characters) and a positive `seq`.
`game_start` is sequence 1. Retries and replay send the exact original JSON;
sequence numbers are never reassigned. Player snapshots still reflect capture
time; no client timestamp has been added and API receipt times retain their
existing meaning.
A single sender keeps `game_start` and `game_end` at the queue head on transport
failure, native timeout, HTTP 429 or 5xx. Delays are 1, 2, 4, 8, 16, then 30 seconds
between attempts, capped at 30 seconds without a retry-count limit. Other 4xx
(and redirects) are logged and dropped. A 2xx with a JSON boolean `"ok": true`
acknowledges delivery; empty, malformed or negative 2xx replies and missing HTTP
diagnostics are unacknowledged and retried for boundaries. Accepted reports log
Electric Cherry's `telemetry.timing.matchId` as `ec_match_id` when supplied.
Heartbeats and round changes remain best effort. Waiting heartbeats are coalesced
to the newest snapshot, preserving round reports and any in-flight request.
Intentional coalescing can produce gaps in `seq`.
The native outbox saves start/end snapshots synchronously before sending, and
removes them only after acknowledgment or a terminal HTTP rejection. Files live
under `fs_homepath/tws-telemetry/t5/` or `t6/`, scoped to the exact server name and
endpoint. Keep this directory on persistent writable storage across process or
container restarts; it contains player snapshots but no authorization token.
Use a single process per server/endpoint and storage directory. Endpoint/server
changes use a separate outbox, so restore the original configuration to replay
its backlog. Keep `tws_server_id` stable between maps. On map/process startup,
recovered boundaries precede any new `game_start`. An accepted report whose
acknowledgment/removal was lost is safely replayed with the same identity.
Writes replace the committed file only after a complete temporary write. A
storage error blocks the affected boundary before sending and logs an error;
unsaved in-memory reports cannot survive a restart. Unreadable/corrupt saved data
disables telemetry until storage is repaired and the map restarted, preserving
the file for recovery. Each outbox is limited to 4,096 reports / 16 MiB, with
individual report bodies below 20 KiB; reaching a limit fails visibly without
discarding the saved backlog. Disk removal failures retry cleanup without sending
an already resolved report again during the same map. The plugin cannot recover
a `game_end` that was never captured (for example, a process crash during play).
Run `node tools/check_telemetry.mjs` for both reporters' queue/retry fixtures and
`python3 tools/test_plugin_telemetry.py` for native storage, acknowledgment and
process-restart checks with sanitizers. The native test uses each restored JSON
dependency; alternatively pass `--json-header '/path/{game}-json.hpp'` with the
single headers from each plugin's pinned revision. These tests use engine shims.
Validate Windows DLL linking and both games in Plutonium before rollout: force a
timeout/429/503 at start and end, confirm permanent 400/401 failures do not retry,
restart a map and then a process with pending boundaries, and confirm their
original match IDs complete before the next start. Also verify a 2xx without
`ok: true` stays pending, an outage retains only the latest waiting heartbeat,
and a disk failure is visible without advancing past an unsaved boundary.
## Parity
@@ -141,7 +203,7 @@ cleanup. Disable the leaderboard module and verify `.leaders` is absent from hel
Both reporters default to `https://ec.thewrightserver.net/api/telemetry` and send
`Authorization: Bearer <token>` plus `Content-Type: application/json` on every
POST. Existing event fields and queue behavior are unchanged. An explicit
POST. Authentication is also used for retried/replayed reports. An explicit
`tws_telemetry_url` override must also use HTTPS; remove any old HTTP override.
Before upgrading the API or loading these reporters: