feat(bot): Telegram bot Bot API health over the bot-link (metrics + alerts) #245

Merged
developer merged 2 commits from feature/bot-health-telemetry into development 2026-07-11 10:58:01 +00:00
Owner

Why

The Telegram bot runs on its own host and exports no telemetry (otelcol is on the main host, unreachable) — a monitoring blind spot. This makes it observable from the main host's Grafana without opening any port on the bot or shipping OTLP: the bot relays its Bot API health up the existing bot-link, and the gateway turns it into metrics + alerts.

PR1 of 2 (the second is the edge community blocklist).

Design (as agreed)

Boot order untouched (the bot must keep working when the gateway/game is down). Health is captured centrally by wrapping the Bot API HTTP client — no per-call-site edits across ~23 sites — which cleanly gives all four signals and solves idle-liveness (the getUpdates long-poll returns a 2xx every poll, even with no updates, so the last-ok stamp stays fresh).

  • proto: Health{connect_failures, api_errors, rate_limited, last_ok_unix} added to the FromBot oneof (additive → rolling-safe across the two hosts).
  • bot (internal/health): the HTTP wrapper stamps liveness on any 2xx, classifies transport/5xx failures (getUpdates → connect vs other → api) and 429s, and honours a 429's Retry-After (bounded by 30s) so the bot backs off — 429 should therefore stay ~0. A 4xx other than 429 (user blocked the bot, bad request) is a normal outcome, not counted.
  • bot-link client: flushes deltas as a Health every 30s over a single-sender loop (a gRPC stream forbids concurrent Send); a failed flush loses nothing (commit-on-success).
  • gateway: folds reports into bot_tg_errors_total{kind} + the bot_tg_last_ok_unix liveness gauge.

Three layered signals (compose, don't overlap)

  • botlink_connected_botsbot/link/host down.
  • bot_tg_last_ok_unix staleness → silently wedged bot (fresh even when idle).
  • botlink_commands_total{result}gateway sends failing to reach Telegram.

Alerts (bot disconnected / not reaching the Bot API / sustained 429) route to the operator email — which does not go through the bot, so a bot-down alert is deliverable. A Telegram bot dashboard shows all of it.

Verification (local)

gofmt/vet clean · buf generate (committed) · all four modules build · unit tests: observer classification (2xx→liveness, poll-5xx→connect, send-5xx→api, 429→rate_limited, 4xx ignored, shutdown ignored), Retry-After parsing (header + body), snapshot/commit, hub last-ok monotonicity · full gateway + telegram suites green.

Note

Additive proto → a rolling deploy is safe, but prod carries two hosts (main + bot); deploy both so the bot ships the new Health. The bot host runs docker-compose.bot.yml (manual).

## Why The Telegram bot runs on its **own host** and exports **no telemetry** (otelcol is on the main host, unreachable) — a monitoring blind spot. This makes it observable from the main host's Grafana **without** opening any port on the bot or shipping OTLP: the bot relays its Bot API health up the **existing bot-link**, and the gateway turns it into metrics + alerts. PR1 of 2 (the second is the edge community blocklist). ## Design (as agreed) Boot order **untouched** (the bot must keep working when the gateway/game is down). Health is captured **centrally** by wrapping the Bot API HTTP client — no per-call-site edits across ~23 sites — which cleanly gives all four signals and solves idle-liveness (the `getUpdates` long-poll returns a 2xx every poll, even with no updates, so the last-ok stamp stays fresh). - **proto**: `Health{connect_failures, api_errors, rate_limited, last_ok_unix}` added to the `FromBot` oneof (additive → rolling-safe across the two hosts). - **bot** (`internal/health`): the HTTP wrapper stamps liveness on any 2xx, classifies transport/5xx failures (`getUpdates` → connect vs other → api) and 429s, and **honours a 429's Retry-After** (bounded by 30s) so the bot backs off — 429 should therefore stay ~0. A 4xx other than 429 (user blocked the bot, bad request) is a normal outcome, not counted. - **bot-link client**: flushes deltas as a `Health` every 30s over a **single-sender loop** (a gRPC stream forbids concurrent Send); a failed flush loses nothing (commit-on-success). - **gateway**: folds reports into `bot_tg_errors_total{kind}` + the `bot_tg_last_ok_unix` liveness gauge. ## Three layered signals (compose, don't overlap) - `botlink_connected_bots` → **bot/link/host down**. - `bot_tg_last_ok_unix` staleness → **silently wedged bot** (fresh even when idle). - `botlink_commands_total{result}` → **gateway sends failing to reach Telegram**. Alerts (bot disconnected / not reaching the Bot API / sustained 429) route to the **operator email** — which does not go through the bot, so a bot-down alert is deliverable. A `Telegram bot` dashboard shows all of it. ## Verification (local) `gofmt`/`vet` clean · `buf generate` (committed) · all four modules build · unit tests: observer classification (2xx→liveness, poll-5xx→connect, send-5xx→api, 429→rate_limited, 4xx ignored, shutdown ignored), Retry-After parsing (header + body), snapshot/commit, hub last-ok monotonicity · full gateway + telegram suites green. ## Note Additive proto → a rolling deploy is safe, but prod carries **two hosts** (main + bot); deploy both so the bot ships the new `Health`. The bot host runs `docker-compose.bot.yml` (manual).
developer added 1 commit 2026-07-11 10:48:32 +00:00
feat(bot): report Telegram bot Bot API health to the gateway over the bot-link
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 12s
CI / integration (pull_request) Successful in 26s
CI / ui (pull_request) Successful in 1m11s
CI / conformance (pull_request) Successful in 10s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m56s
bb71e7b1c7
The bot runs on its own host and exports no telemetry (otelcol is unreachable
from there), so it was a monitoring blind spot. Observe its Bot API health
centrally by wrapping the HTTP client — one place, no per-call-site
instrumentation — and relay it up the existing bot-link as a periodic Health
message the gateway turns into its own metrics.

- proto: add Health (delta connect / api / 429 counters + a last-ok stamp) to
  the FromBot oneof (additive, backward-compatible).
- bot: platform/telegram/internal/health wraps the Bot API HTTP client — it
  stamps liveness on any 2xx (so the getUpdates long-poll keeps it fresh even
  when idle), classifies transport/5xx failures (getUpdates vs other) and 429s,
  and honours a 429's Retry-After (bounded) so the bot backs off; a 4xx other
  than 429 is a normal per-request outcome and is not counted.
- bot-link client: flush the reporter as a Health message every 30s over a
  single-sender loop (a gRPC stream forbids concurrent Send).
- gateway: fold each report into bot_tg_errors_total{kind} and the
  bot_tg_last_ok_unix liveness gauge.
- grafana: alerts (bot disconnected, bot not reaching the Bot API, sustained
  429s) routed to the operator email — which does not go through the bot — plus
  a Telegram-bot dashboard.
- docs (ARCHITECTURE, compose comments); unit tests (observer classification,
  Retry-After, snapshot/commit, hub last-ok monotonicity).
developer added 1 commit 2026-07-11 10:53:37 +00:00
chore(catalog): order the admin catalog list like the public offer
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 26s
CI / ui (pull_request) Successful in 1m11s
CI / conformance (pull_request) Successful in 9s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Successful in 1m50s
2c2316fb5e
Sales (chip packs) first, ascending by rouble price; then the chip-exchange
values, grouped and price-sorted the same way projectOfferPricing lists them, so
the /catalog console mirrors what a buyer sees. Internal cosmetics only — no
product behaviour change. The value-group order moves to a shared helper
(valueGroup) so the offer and the admin list cannot drift.
owner approved these changes 2026-07-11 10:54:57 +00:00
developer merged commit ad1cc361e9 into development 2026-07-11 10:58:01 +00:00
developer deleted branch feature/bot-health-telemetry 2026-07-11 10:58:01 +00:00
Sign in to join this conversation.
No Reviewers
No Label
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: developer/scrabble-game#245