feat: hot-reloaded runtime config (src/lib/runtime-config.ts), greeting on GET /, GET /admin/runtime-config
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
cff850544d
commit
bd2d5978a2
13 changed files with 511 additions and 10 deletions
24
README.md
24
README.md
|
|
@ -6,7 +6,8 @@ Express 5 + TypeScript backend generated from `nholtware/service-template-expres
|
|||
|
||||
- `GET /healthz` liveness, always 200 once listening
|
||||
- `GET /readyz` readiness: Postgres `SELECT 1` and Redis `PING` for whichever of `DATABASE_URL` / `REDIS_URL` are set; 503 + JSON reason otherwise
|
||||
- `GET /` service name, version (git sha), pod, a `service_info` row, Redis hit counter, and `banner` while the `hello-banner` flag is on
|
||||
- `GET /` service name, version (git sha), pod, `greeting` (runtime config), a `service_info` row, Redis hit counter, and `banner` while the `hello-banner` flag is on
|
||||
- `GET /admin/runtime-config` current runtime config `values`, `loadedAt`, `source` (`file` | `defaults`)
|
||||
- `GET /log-demo?msg=...` logs `{ demo: true, text }` with message `log-demo` (logging-pipeline demo; delete when you don't need it)
|
||||
|
||||
## Local dev
|
||||
|
|
@ -17,7 +18,7 @@ npm ci && npm run dev
|
|||
npm run lint && npm test
|
||||
```
|
||||
|
||||
Env is validated at boot (`src/lib/config.ts`): `PORT`, `SERVICE_NAME` (required), `LOG_LEVEL`, `DATABASE_URL?`, `REDIS_URL?`, `UNLEASH_URL?`, `UNLEASH_API_TOKEN?` (required with `UNLEASH_URL`), `UNLEASH_REFRESH_MS` (default 5000).
|
||||
Env is validated at boot (`src/lib/config.ts`): `PORT`, `SERVICE_NAME` (required), `LOG_LEVEL`, `DATABASE_URL?`, `REDIS_URL?`, `UNLEASH_URL?`, `UNLEASH_API_TOKEN?` (required with `UNLEASH_URL`), `UNLEASH_REFRESH_MS` (default 5000), `RUNTIME_CONFIG_PATH?`.
|
||||
Migrations: SQL files in `migrations/`, applied with `npm run migrate`.
|
||||
Logs: one JSON object per line on stdout (`level,time,msg,service,version`, plus `req.*`/`res.statusCode`/`responseTime` per request).
|
||||
|
||||
|
|
@ -54,6 +55,25 @@ const v = deps.flags?.getVariant("my-experiment"); // v.name, v.enabled, v.paylo
|
|||
- Tests: pass a fake `Flags` to `createApp` (see `src/app.test.ts`); never hit a real Unleash.
|
||||
- `hello-banner` on `GET /` is the platform demo flag; delete it when you don't need it.
|
||||
|
||||
## Runtime config
|
||||
|
||||
Typed values you change with a git commit, live in running pods without a restart
|
||||
(timeouts, limits, copy; not on/off-for-whom, that's a feature flag; never secrets).
|
||||
|
||||
- Schema + defaults: `src/runtime-config.schema.ts` (zod). Every key needs a default.
|
||||
- Read it per request: `deps.runtimeConfig.get().maxItems`. React to changes with
|
||||
`runtimeConfig.onChange((values, changedKeys) => ...)`.
|
||||
- In the cluster: ConfigMap `<app>-runtime-config` (key `runtime.yaml`) in gitops
|
||||
`manifests/<app>/runtime-config.yaml`, mounted as a directory at `/etc/app/`,
|
||||
`RUNTIME_CONFIG_PATH=/etc/app/runtime.yaml`. Edit, commit, push: live within ~4 min
|
||||
(ArgoCD polls every 3 min, kubelet refreshes the volume within ~1 min).
|
||||
Log line `runtime config reloaded` lists `changedKeys`.
|
||||
- A bad value (invalid YAML, fails the schema) keeps the last good values and logs `error`
|
||||
with the zod issues. The pod never crashes on a config commit. Fix it with another commit.
|
||||
- Local dev: `RUNTIME_CONFIG_PATH=./runtime.yaml npm run dev`; edits reload immediately.
|
||||
Unset = schema defaults (`source: "defaults"`).
|
||||
- `GET /admin/runtime-config` is unauthenticated, which is why nothing secret goes in here.
|
||||
|
||||
## Using this template
|
||||
|
||||
1. **Generate** a repo from this template in Forgejo (public). The repo name is substituted into `package.json`, this README, `.env.example`, and the first migration (CI derives the app name from the repo name itself).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue