fix(renderer): pre-render the static legal pages at boot
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 19s
CI / ui (pull_request) Successful in 1m13s
CI / conformance (pull_request) Successful in 11s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Failing after 2m28s
CI / changes (pull_request) Successful in 2s
CI / unit (pull_request) Successful in 11s
CI / integration (pull_request) Successful in 19s
CI / ui (pull_request) Successful in 1m13s
CI / conformance (pull_request) Successful in 11s
CI / gate (pull_request) Successful in 0s
CI / deploy (pull_request) Failing after 2m28s
Serving /eula/ re-parsed the large (~122 KB) EULA markdown on every request. Under the rolling deploy's host contention (the renderer is capped at 1 CPU / 192 MB) that was slow enough that the contour /eula/ probe failed for its whole 60s retry window, while the smaller /privacy/ squeaked through; both serve fine once the host is idle. Render privacy + eula once at boot and serve the cached HTML (now ~1.5 ms, a memcpy). The offer stays per-request for its live price splice; the probe retry stays as a readiness backstop.
This commit is contained in:
+1
-1
@@ -21,7 +21,7 @@ signed off) and the public **legal pages** (the offer, the privacy policy and th
|
|||||||
here; a backend outage yields a 502, never a stale price list.
|
here; a backend outage yields a 502, never a stale price list.
|
||||||
- `GET /privacy/` — the privacy policy, and `GET /eula/` the end-user licence agreement, both as
|
- `GET /privacy/` — the privacy policy, and `GET /eula/` the end-user licence agreement, both as
|
||||||
`text/html`: the owner-edited `ui/legal/privacy_ru.md` / `ui/legal/eula_ru.md` (baked in, read at
|
`text/html`: the owner-edited `ui/legal/privacy_ru.md` / `ui/legal/eula_ru.md` (baked in, read at
|
||||||
boot), rendered by the same shared `renderLegalHtml`. **Static** — no backend fetch. `GET /privacy`
|
boot), rendered once at boot by the same shared `renderLegalHtml` and served from cache. **Static** — no backend fetch. `GET /privacy`
|
||||||
/ `GET /eula` → 301 to the trailing-slash form. Caddy routes these here too.
|
/ `GET /eula` → 301 to the trailing-slash form. Caddy routes these here too.
|
||||||
- `GET /healthz` — liveness (the compose healthcheck the backend's `depends_on` gates on).
|
- `GET /healthz` — liveness (the compose healthcheck the backend's `depends_on` gates on).
|
||||||
|
|
||||||
|
|||||||
@@ -33,6 +33,12 @@ const OFFER_MD = readFileSync(process.env.RENDERER_OFFER_MD || new URL('../legal
|
|||||||
// boot, no dynamic data. RENDERER_PRIVACY_MD / RENDERER_EULA_MD override the baked path for a local run.
|
// boot, no dynamic data. RENDERER_PRIVACY_MD / RENDERER_EULA_MD override the baked path for a local run.
|
||||||
const PRIVACY_MD = readFileSync(process.env.RENDERER_PRIVACY_MD || new URL('../legal/privacy_ru.md', import.meta.url), 'utf8');
|
const PRIVACY_MD = readFileSync(process.env.RENDERER_PRIVACY_MD || new URL('../legal/privacy_ru.md', import.meta.url), 'utf8');
|
||||||
const EULA_MD = readFileSync(process.env.RENDERER_EULA_MD || new URL('../legal/eula_ru.md', import.meta.url), 'utf8');
|
const EULA_MD = readFileSync(process.env.RENDERER_EULA_MD || new URL('../legal/eula_ru.md', import.meta.url), 'utf8');
|
||||||
|
// Render the static legal pages once at boot and serve the cached HTML: they carry no dynamic data,
|
||||||
|
// and re-parsing the large EULA markdown on every request is slow enough under deploy-time host
|
||||||
|
// contention (the renderer is CPU/memory-capped) to flake the contour probe. The offer stays
|
||||||
|
// per-request because it splices in the live price list.
|
||||||
|
const PRIVACY_HTML = renderPrivacy(PRIVACY_MD);
|
||||||
|
const EULA_HTML = renderEula(EULA_MD);
|
||||||
const OFFER_PRICING_URL =
|
const OFFER_PRICING_URL =
|
||||||
(process.env.RENDERER_BACKEND_URL || 'http://backend:8080') + '/api/v1/internal/offer/pricing';
|
(process.env.RENDERER_BACKEND_URL || 'http://backend:8080') + '/api/v1/internal/offer/pricing';
|
||||||
|
|
||||||
@@ -89,13 +95,13 @@ const server = createServer(async (req, res) => {
|
|||||||
if (req.method === 'GET' && path === '/privacy/') {
|
if (req.method === 'GET' && path === '/privacy/') {
|
||||||
res
|
res
|
||||||
.writeHead(200, { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-cache' })
|
.writeHead(200, { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-cache' })
|
||||||
.end(renderPrivacy(PRIVACY_MD));
|
.end(PRIVACY_HTML);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (req.method === 'GET' && path === '/eula/') {
|
if (req.method === 'GET' && path === '/eula/') {
|
||||||
res
|
res
|
||||||
.writeHead(200, { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-cache' })
|
.writeHead(200, { 'content-type': 'text/html; charset=utf-8', 'cache-control': 'no-cache' })
|
||||||
.end(renderEula(EULA_MD));
|
.end(EULA_HTML);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (req.method === 'POST' && path === '/render') {
|
if (req.method === 'POST' && path === '/render') {
|
||||||
|
|||||||
Reference in New Issue
Block a user