-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathcodexbar-warm.sh
More file actions
executable file
·125 lines (117 loc) · 5.45 KB
/
Copy pathcodexbar-warm.sh
File metadata and controls
executable file
·125 lines (117 loc) · 5.45 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/env bash
# codexbar-warm.sh — keep `codexbar serve`'s snapshot recent enough that the
# dashboard's rows are fresh when it reads them.
#
# WHY THIS EXISTS (2026-08-27)
# ----------------------------
# `codexbar serve` refreshes LAZILY, not on a background interval. It answers
# GET /usage with the last COMPLETED snapshot and only then starts a new one, so
# the timestamp it returns is the time of the PREVIOUS request. Measured on this
# host: a poll at 12:04:40 returned updatedAt 12:02:25; after 200 seconds with
# no traffic, the next poll returned 12:04:41 — exactly the earlier poll's time.
# Nothing had refreshed in between. `--refresh-interval 60` does not drive a
# loop while the server is idle.
#
# That interacts badly with how the desk reads it. A row's `observed_at` is
# CodexBar's own `usage.updatedAt`, and `stale_at` is that plus ten minutes. The
# desk probes at most once every five minutes and only when a row is already not
# fresh — so it was the *only* thing polling CodexBar, and each probe therefore
# returned a snapshot stamped at the previous probe, five or more minutes
# earlier. Rows were written already half-expired and spent much of every cycle
# marked stale. The Ollama reader stamps its own fetch time, so it never lagged,
# which is what made the contrast visible: one fresh row beside five stale ones.
#
# One request a minute is enough to fix it: every desk probe then finds a
# snapshot a minute or two old rather than five-plus, and the row is fresh for
# nearly its whole ten-minute window.
#
# This is a workaround for upstream behaviour, not a desk feature — nothing in
# ORDERLY changed to accommodate it. If a future CodexBar refreshes on its own
# interval while idle, this unit becomes redundant and should be removed.
ENDPOINT="${CODEXBAR_WARM_ENDPOINT:-http://127.0.0.1:18791}"
INTERVAL="${CODEXBAR_WARM_INTERVAL:-60}"
# The providers the dashboard actually configures. Warming only these keeps the
# cost to one cheap request each rather than sweeping CodexBar's whole catalogue.
PROVIDERS="${CODEXBAR_WARM_PROVIDERS:-codex claude kimi zai cursor}"
CODEXBAR_WARM_FAILURES=0
CODEXBAR_WARM_LAST_RESTART=""
codexbar_warm_now() {
# OS monotonic time: wall-clock corrections must not shorten the cooldown.
node -e 'process.stdout.write(String(process.hrtime.bigint() / 1000000000n))'
}
codexbar_warm_health() {
# Node is already ORDERLY's runtime. If unavailable in this unit's PATH,
# disable recovery instead of mistaking a missing parser for a broken server.
command -v node >/dev/null 2>&1 || return 2
local response
response="$(curl -sS --fail --max-time 10 --max-filesize 4096 \
--write-out '\n%{http_code}' "${ENDPOINT}/health" 2>/dev/null)" || return 1
printf '%s' "$response" | node -e '
try {
const text = require("node:fs").readFileSync(0, "utf8");
const split = text.lastIndexOf("\n");
const health = JSON.parse(text.slice(0, split));
process.exit(text.slice(split + 1) === "200" &&
health?.status === "ok" && health?.version === "0.49.6" ? 0 : 1);
} catch { process.exit(1); }
' >/dev/null 2>&1
}
codexbar_warm_recover() {
local now state
(( CODEXBAR_WARM_FAILURES >= 3 )) || return 0
now="$(codexbar_warm_now 2>/dev/null)" || return 0
[[ "$now" =~ ^[0-9]+$ ]] || return 0
if [[ -n "$CODEXBAR_WARM_LAST_RESTART" ]] &&
(( now - CODEXBAR_WARM_LAST_RESTART < 900 )); then
return 0
fi
state="$(systemctl --user show --property=ActiveState --value \
codexbar-serve.service 2>/dev/null)" || return 0
[[ "$state" == active ]] || return 0
# Never start an intentionally stopped reader. try-restart also protects the
# inactive case if the operator stops it after the state check. Count attempts,
# including failed ones, and leave no provider response in the journal.
CODEXBAR_WARM_LAST_RESTART="$now"
CODEXBAR_WARM_FAILURES=0
systemctl --user try-restart --no-block codexbar-serve.service >/dev/null 2>&1 || true
}
codexbar_warm_cycle() {
local health_result=0 provider status providers_seen=0 responsive=0
codexbar_warm_health || health_result=$?
for provider in $PROVIDERS; do
(( providers_seen += 1 ))
# Read-only, loopback, unauthenticated, and the body is discarded: this exists
# purely so the server starts its next refresh. Reuse its HTTP status, never
# its provider body: even auth/rate-limit errors prove that route responds.
status="$(curl -sS --max-time 30 -o /dev/null --write-out '%{http_code}' \
"${ENDPOINT}/usage?provider=${provider}" 2>/dev/null)" || true
if [[ "$status" =~ ^[1-5][0-9][0-9]$ && "$status" != 504 ]]; then
responsive=1
fi
done
# The parser/runtime being unavailable is not evidence against the reader.
if (( health_result != 0 && health_result != 1 )); then
CODEXBAR_WARM_FAILURES=0
return 0
fi
# /health can answer while every usage route is wedged. Only a whole nonempty
# warming cycle of transport failures/504s adds that availability evidence;
# one responsive provider breaks the all-routes-hung condition. Count each
# cycle once and make one recovery decision, even if both checks fail.
if (( health_result == 1 || (providers_seen > 0 && responsive == 0) )); then
(( CODEXBAR_WARM_FAILURES < 3 )) && (( CODEXBAR_WARM_FAILURES += 1 ))
else
CODEXBAR_WARM_FAILURES=0
fi
codexbar_warm_recover
}
codexbar_warm_main() {
set -uo pipefail
while :; do
codexbar_warm_cycle
sleep "$INTERVAL"
done
}
if [[ "${BASH_SOURCE[0]}" == "$0" ]]; then
codexbar_warm_main
fi