feat: add /health endpoint + Docker HEALTHCHECK#20
Merged
Conversation
Mirrors the pattern recently shipped in discord-bot-starter (#24) so Fly.io / Railway / Docker can detect a crashed or disconnected bot. - `src/lib/health.js` — zero-dep http server. Readiness reads `bot.isRunning()` in polling mode and `bot.isInited()` in webhook mode. Also exports `createHealthHandler` so webhook mode can mount /health on the existing webhook server instead of opening a second port. - `src/index.js` — polling mode spins up a standalone health server on HEALTH_PORT; webhook mode composes /health onto the webhookCallback handler. Shutdown closes both cleanly. - `Dockerfile` — `EXPOSE 3000` + `HEALTHCHECK wget --spider` on HEALTH_PORT. Alpine ships wget, so no extra package. - `.env.example` — document HEALTH_PORT. - READMEs (EN + KR) — new Health Check section with Fly.io `[[http_service.checks]]` + Railway snippets. - `tests/health.test.js` — ephemeral-port integration tests for 200/503/404 in polling mode plus 200/503 + fallback delegation in webhook-mount mode. - `tests/commands.test.js` — existing structural tests were identity checks. Upgraded with real mock-ctx unit tests for /start (reply text + error-swallow) and /help (real loader feeds real command list into the reply). Structure checks retained.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Mirrors the pattern just landed in
discord-bot-starter(#24) so Fly.io / Railway / Docker can detect a crashed or disconnected bot.src/lib/health.js— zero-dephttpserver. Readiness isbot.isRunning()in polling mode andbot.isInited()in webhook mode. Exports bothcreateHealthServer(standalone) andcreateHealthHandler(mount on an existing server).src/index.js— polling mode runs a standalone health server onHEALTH_PORT; webhook mode mounts/healthon the existing grammYwebhookCallbackserver instead of spawning a second listener (keeps the container single-port — important for Fly.io[[http_service]]and Railway's one-port-per-service model).Dockerfile—EXPOSE 3000+HEALTHCHECK wget --spider. Alpine ships wget, no extra package..env.example—HEALTH_PORT=3000with a comment.[[http_service.checks]]+ Railway instructions.Tests
tests/health.test.js(new) — ephemeral-port (port: 0) integration tests against a realhttp.getclient. Covers 200 + JSON shape when ready, 503 when not, 404 for unknown paths, and in webhook-mount mode also verifies fallback delegation so/healthdoesn't shadow the webhook route.tests/commands.test.js— audit finding: the previous file was structural identity checks only (toHaveProperty('name')). Upgraded /start and /help to real mock-ctx unit tests (reply-text assertion, error-swallow check, and a /help test that runs the real loader and asserts every registered command appears in the reply). Structural checks retained so new commands keep getting shape-validated.All 14 tests pass locally; lint clean.
Test plan
npm run lintcleannpm testall green locally (14/14)docker build+docker runshows(healthy)within the start-period (left to the reviewer — local Docker smoke test)Implementation notes for reviewers
bot.isRunning(), which flips true as soon asbot.start()enters its polling loop (beforeonStartfires) — exactly the readiness semantics we want for orchestrators.bot.isInited()because the bot never calls.start()—setWebhookis a one-shot API call.isInited()goes true after grammY auto-fetches bot identity on the first update.bot.stop()→process.exit(0).