Skip to content

feat(services): nginx as the other front end, and the rule that there is one (T37) - #9

Merged
haiquang9994 merged 5 commits into
masterfrom
feat/nginx-front-end
Aug 21, 2026
Merged

feat(services): nginx as the other front end, and the rule that there is one (T37)#9
haiquang9994 merged 5 commits into
masterfrom
feat/nginx-front-end

Conversation

@haiquang9994

Copy link
Copy Markdown
Collaborator

Closes T37: nginx as the alternative front end, plus a parity suite that drives both generators through one arc.

What is here

The recipe. nginx.conf is rendered from the service's row and settings: foreground (daemon off;), error log on the stream mix service logs reads, pid under run/ rather than the compiled-in logs/nginx.pid-s reload and -s quit find the master through the pid file this configuration names — and the five temp directories as children of the data directory, because nginx makes each with a single mkdir. Every path is forward-slashed and quoted: ngx_conf_read_token treats a backslash inside a quoted string as an escape.

One front end, and a rule that can say so. Instancing is about a package — how many rows may name nginx — and both front ends answer Single, so a home obeying both recipes still ends up with a Caddy and an nginx rendered against the same ports. Recipe::role() is the missing distinction: FrontEnd or Other, defaulted to the second so a recipe added later opts into the exclusivity rather than remembering to opt out. service.create refuses the second one, by role rather than by name.

nginx has no admin endpoint, so the recipe renders one. A TCP accept is not a substitute — the master holds the listening socket, so it succeeds in exactly the same way when every worker has died. The template writes a loopback server answering 200 on /mixengine/health, which is a request a worker reading this configuration served, and it backs both the ready check and the health probe.

The parity suite. The sequence a front end has to walk lives in tests/harness/frontend.rs and is driven twice; caddy.rs and nginx.rs are each four constants over it. Two copies of that arc would drift, and the copy that drifted would be green while it did.

What the Windows leg found

Two follow-ups came out of CI rather than out of the design.

nginx -t reports a failure on its first line and a summary on its last, the opposite of caddy validate. Reported by the last line, every nginx configuration error would have read as something is wrong somewhere: Validator::reason says where a program leaves its answer.

And nginx refuses any file reached through a Windows 8.3 alias — ngx_win32_check_filename expands the name it was handed and reports ENOENT when the expansion differs, so a home under RUNNER~1 is a home whose every rendered file is "missing" while it sits on disk. mixengine_platform::paths::in_full spells a path the way the filesystem does, and both resolve_roots apply it: everything is joined onto that one answer, and mix and mixengined have to agree on it exactly because the endpoint is derived from it.

Verification

All seven CI jobs green. The real-nginx suite runs on all three systems (2 passed on each), the Linux one inside the no-network namespace.

… is one (T37)

Adds the nginx recipe beside Caddy, and `Recipe::role` — the answer to a
question `Instancing` cannot ask, since both front ends run as a single
instance yet a home may only have one program reached on 80 and 443.
`service.create` refuses the second, before the package check, because
installing it would not have helped.

nginx has no admin endpoint, so the template renders a loopback status
server and the readiness and health checks point at it: the master holds
the listening socket, so a TCP accept succeeds identically when every
worker is dead.

The Caddy suite's arc moves to `tests/harness/frontend.rs` and is driven
twice — generate, validate, start, serve, reload, refuse a broken
override, stop — which is the parity the roadmap asked for. CI fetches a
pinned nginx on all three systems the way it already fetches Caddy.
nginx refuses a configuration in two lines — the reason, then
`configuration file <path> test failed` — and the second is a summary
that names the file the message around it already names. Reported by its
last line, as every other validator wants to be, an nginx failure said
only that something somewhere was wrong.

`Validator::reason` says which end carries it; `Ran::complaints` hands
back the whole of the stream so the stream is chosen once rather than at
each call site. `fakeservice --complain` stages a refusal from both ends,
which is what the two new tests drive.
nginx checks every file it opens for reading with `ngx_win32_check_filename`,
which expands the name it was given and reports ENOENT when the expansion is
not what it was handed. A home under a Windows 8.3 alias — `%TEMP%` on a
GitHub runner is `C:\Users\RUNNER~1\...` — is therefore a home whose every
rendered configuration is refused as missing while it sits on disk.

`mixengine_platform::paths::in_full` spells a path the way the filesystem
spells it, and both `resolve_root`s apply it: one spelling at the top makes
`etc/`, `data/` and `packages/` long, and keeps `mix` and `mixengined`
deriving one endpoint rather than two.
@haiquang9994
haiquang9994 merged commit e72b645 into master Aug 21, 2026
7 checks passed
@haiquang9994
haiquang9994 deleted the feat/nginx-front-end branch August 21, 2026 16:42
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant