5.3 KiB
5.3 KiB
Current Match AdminLog Freshness
Problem
The public current-match page was lagging because:
/api/current-match/killsreads persistedrcon_admin_log_events/api/current-match/playersreads persistedrcon_admin_log_events- those endpoints do not ingest AdminLog during the request path
- the checked-in historical worker path refreshes AdminLog on a much slower cadence
- frontend polling was already faster than backend data freshness
Observed behavior from TASK-268 matched this design:
- checked-in historical worker interval:
600seconds - checked-in AdminLog lookback:
10minutes - observed public lag growing from about
333sto about651s
Solution
Add a dedicated lightweight worker:
- module:
python -m app.rcon_current_match_worker - scope: only trusted current-match servers
comunidad-hispana-01comunidad-hispana-02
- fetches recent AdminLog directly from existing configured RCON targets
- reuses existing parsing and
persist_rcon_admin_log_entries(...) - writes into the same
rcon_admin_log_eventstable - relies on existing dedupe/idempotency for overlap-safe windows
Default worker settings:
CURRENT_MATCH_ADMINLOG_INTERVAL_SECONDS=10CURRENT_MATCH_ADMINLOG_LOOKBACK_SECONDS=180CURRENT_MATCH_ADMINLOG_ENABLED=false
The worker is opt-in. This task does not change Compose to start it automatically.
Design Notes
The worker intentionally avoids:
- changing RCON hosts, ports or passwords
- introducing a second AdminLog schema
- reducing the heavy historical worker interval globally
- pushing ingestion into
/api/current-match/*request handlers
Each iteration:
- filters configured RCON targets down to trusted current-match servers
- fetches recent AdminLog entries with a small overlap window
- persists through the existing idempotent storage path
- logs per-target counts for:
entries_seenevents_insertedduplicate_eventsduration_ms
- continues if one server fails
Run Commands
Local one-shot validation:
cd backend
python -m app.rcon_current_match_worker once
Local loop:
cd backend
python -m app.rcon_current_match_worker loop --interval 10 --lookback-seconds 180
Docker/Compose-style ad hoc command without changing deployment defaults:
docker compose run --rm backend python -m app.rcon_current_match_worker loop --interval 10 --lookback-seconds 180
Example service snippet for a future approved deployment:
current-match-adminlog-worker:
profiles: ["advanced"]
build:
context: ./backend
command: ["python", "-m", "app.rcon_current_match_worker", "loop"]
environment:
HLL_BACKEND_DATABASE_URL: ${HLL_BACKEND_DATABASE_URL}
HLL_BACKEND_RCON_TARGETS: ${HLL_BACKEND_RCON_TARGETS}
CURRENT_MATCH_ADMINLOG_ENABLED: ${CURRENT_MATCH_ADMINLOG_ENABLED:-false}
CURRENT_MATCH_ADMINLOG_INTERVAL_SECONDS: ${CURRENT_MATCH_ADMINLOG_INTERVAL_SECONDS:-10}
CURRENT_MATCH_ADMINLOG_LOOKBACK_SECONDS: ${CURRENT_MATCH_ADMINLOG_LOOKBACK_SECONDS:-180}
The snippet is documented only. It is not applied automatically by this task.
Post-Deployment Validation
Watch worker logs for per-target counts and errors. The useful signals are:
entries_seenevents_insertedduplicate_eventstarget_keyduration_ms
Sample the public API every 10 seconds:
$killsBase = "https://comunidadhll.devzamode.es/api/current-match/kills?server=comunidad-hispana-02&limit=18"
$playersBase = "https://comunidadhll.devzamode.es/api/current-match/players?server=comunidad-hispana-02"
1..18 | ForEach-Object {
$now = Get-Date
$ts = [DateTimeOffset]::UtcNow.ToUnixTimeMilliseconds()
$kills = Invoke-RestMethod "$killsBase&_ts=$ts" -Headers @{ "Cache-Control" = "no-cache"; "Pragma" = "no-cache" }
$killItems = @($kills.data.items)
$topKill = $killItems | Select-Object -First 1
$players = Invoke-RestMethod "$playersBase&_ts=$ts" -Headers @{ "Cache-Control" = "no-cache"; "Pragma" = "no-cache" }
$playerItems = @($players.data.items)
$topPlayers = $playerItems | Sort-Object -Property kills -Descending | Select-Object -First 5 | ForEach-Object {
"$($_.player_name):K=$($_.kills):D=$($_.deaths):Team=$($_.team)"
}
$killLocalTime = ""
$lagSeconds = ""
if ($topKill -and $topKill.server_time) {
$killDate = [DateTimeOffset]::FromUnixTimeSeconds([int64]$topKill.server_time).ToLocalTime()
$killLocalTime = $killDate.ToString("HH:mm:ss")
$lagSeconds = [int](([DateTimeOffset]::Now - $killDate).TotalSeconds)
}
[PSCustomObject]@{
sample = $_
sampled_at = $now.ToString("HH:mm:ss")
kills_scope = $kills.data.scope
kills_count = $killItems.Count
first_id = if ($killItems.Count -gt 0) { $killItems[0].event_id } else { "" }
first_kill_time = $killLocalTime
estimated_lag_seconds = $lagSeconds
first_kill = if ($topKill) { "$($topKill.killer_name)->$($topKill.victim_name):$($topKill.weapon)" } else { "" }
players_count = $playerItems.Count
top_players = ($topPlayers -join " | ")
}
Start-Sleep -Seconds 10
}
Expected outcome after deployment:
- new CRCON kills should appear in
/api/current-match/killswithin roughly10-30seconds /api/current-match/playersshould advance accordingly- the frontend should reflect it without further polling changes