docs(gateway): document gateway.standalone, the per-profile opt-out of the host multiplexer
Flag list entry, the opt-out path in "No new per-profile gateways", what the host does on rescan (<=30s, no restart), what happens when the key is removed while the profile's own gateway runs, and that a standalone profile's cron, webhook ingress and kanban notifications run only under its own gateway.
This commit is contained in:
committed by
Teknium
parent
0238c9d740
commit
a29cc55e3b
@@ -100,17 +100,26 @@ s6 container or Windows Scheduled Tasks). Otherwise it comes up exactly as
|
||||
before — serving the default profile only — and logs the blocker plus the
|
||||
`hermes gateway migrate --multiplex` one-liner. Nothing is changed on disk.
|
||||
|
||||
An **explicit** `true` is never second-guessed:
|
||||
An **explicit** `true` bypasses migration preflight, except for a launching
|
||||
profile that opts out with `gateway.standalone: true`:
|
||||
|
||||
- `gateway.multiplex_profiles: true` (what the migration writes) multiplexes
|
||||
regardless of the preflight — you, or the migration, made the call.
|
||||
- `gateway.multiplex_profiles: false` is **retired**. It used to keep
|
||||
per-profile gateways for good; now it resolves exactly like an unset key and
|
||||
the gateway logs a warning pointing at `hermes gateway migrate --multiplex`.
|
||||
One gateway per host serves every profile — the only way to run a separate
|
||||
per-profile gateway is `--force` (below).
|
||||
Use `gateway.standalone: true` for a deliberate per-profile gateway, or
|
||||
`--force` for the boundary cases below.
|
||||
- `GATEWAY_MULTIPLEX_PROFILES` in the process environment overrides the
|
||||
unset-key decision the same way an explicit `true` does.
|
||||
- `gateway.standalone: true` in a **named** profile's own `config.yaml`
|
||||
(`profiles/<name>/config.yaml`) opts that profile out of the host multiplexer
|
||||
entirely: the host gateway does not serve it, and the profile runs its own
|
||||
gateway without `--force`. Its gateway serves only itself, even if
|
||||
`multiplex_profiles: true` is also set (see
|
||||
[No new per-profile gateways](#no-new-per-profile-gateways)). Set on the
|
||||
default profile it is ignored with a warning — the default profile is the
|
||||
host gateway. There is no environment variable for this key.
|
||||
|
||||
Other processes (`hermes -p <name> gateway start`, the dashboard, `hermes gateway
|
||||
migrate`) never guess how an unset flag was settled: they read the running
|
||||
@@ -124,12 +133,13 @@ only when no gateway runs.
|
||||
- Many low-traffic profiles that don't each justify a full process.
|
||||
- You want a single thing to start, monitor, and restart.
|
||||
|
||||
One-process-per-profile is no longer a supported topology to *choose*: a named
|
||||
One-process-per-profile is no longer a topology to *choose* implicitly: a named
|
||||
profile's `gateway install` / `gateway start` refuses without `--force` (see
|
||||
[No new per-profile gateways](#no-new-per-profile-gateways)). It survives only
|
||||
where a real boundary blocks the fold — a fleet split across UNIX users, or a
|
||||
`HERMES_HOME` outside `<default home>/profiles/` — and there every profile keeps
|
||||
`--force` as its stated path.
|
||||
[No new per-profile gateways](#no-new-per-profile-gateways)). A profile that
|
||||
wants its own gateway opts out with `gateway.standalone: true` in its own
|
||||
`config.yaml`; where a real boundary blocks the fold — a fleet split across
|
||||
UNIX users, or a `HERMES_HOME` outside `<default home>/profiles/` — every
|
||||
profile keeps `--force` as its path.
|
||||
|
||||
### Pinning the flag
|
||||
|
||||
@@ -162,8 +172,9 @@ default gateway serves them. See the contract changes below.
|
||||
|
||||
### No new per-profile gateways
|
||||
|
||||
Because one host gateway serves every profile, a named profile never gets a
|
||||
gateway of its own. `hermes -p coder gateway install` (or `start`, `run`, and
|
||||
By default, one host gateway serves every profile, and a named profile does
|
||||
not get a gateway of its own. Without the opt-out below,
|
||||
`hermes -p coder gateway install` (or `start`, `run`, and
|
||||
the service step of `hermes -p coder setup`) refuses with exit 78 whether or not
|
||||
a host gateway is running right now:
|
||||
|
||||
@@ -184,19 +195,65 @@ a host gateway is running right now:
|
||||
|
||||
A separate per-profile gateway (for a fleet split across UNIX users or a
|
||||
HERMES_HOME outside profiles/) needs --force: hermes -p coder gateway install --force
|
||||
|
||||
Or opt this profile out of the host gateway for good: set
|
||||
gateway.standalone: true in profiles/coder/config.yaml.
|
||||
Wait for the host gateway to rescan (<=30s), or send its rescan-profiles control verb.
|
||||
```
|
||||
|
||||
When the host gateway is already running and serves the profile, the first
|
||||
line reads `The host gateway already serves profile 'coder'.` with the owner's
|
||||
PID and served set, and the pointer is `hermes -p default gateway restart`.
|
||||
The dashboard's **Start** button for a named profile returns the same refusal.
|
||||
`--force` is the one escape: it installs a real per-profile service, and that
|
||||
service (its `ExecStart` carries no `--force`) keeps starting normally afterwards.
|
||||
|
||||
A profile can also get a gateway of its own by authoring the opt-out. Set
|
||||
`gateway.standalone: true` in the profile's own `config.yaml`:
|
||||
|
||||
```yaml
|
||||
# profiles/coder/config.yaml
|
||||
gateway:
|
||||
standalone: true
|
||||
```
|
||||
|
||||
The host gateway then does not serve the profile, and the boot log
|
||||
records `profile 'coder' is standalone (gateway.standalone: true); not served
|
||||
by this gateway`. `hermes -p coder gateway install|start|run` works without
|
||||
`--force`. If the running host still lists the profile in its served set,
|
||||
the command refuses until it rescans: wait for the next rescan (at most 30
|
||||
seconds under normal operation), or send the `rescan-profiles` control verb
|
||||
to the host gateway. No host restart is required.
|
||||
|
||||
Removing the key makes the profile eligible for the host again. While the
|
||||
profile's own gateway is live, the host skips adding it and logs that it must
|
||||
be stopped first. Stop that gateway; the host takes the profile on its next
|
||||
rescan.
|
||||
|
||||
A standalone profile's adapters, cron, webhook ingress and Kanban
|
||||
notifications run only while its own gateway runs, not under the host
|
||||
multiplexer or `hermes serve`. Point webhook clients at the standalone
|
||||
gateway's own listener; the host's `/p/<profile>/` ingress no longer serves
|
||||
it. The cron destination picker still lists standalone profiles as
|
||||
`bot-chat:<name>` targets, but the host cannot deliver to those targets.
|
||||
|
||||
`hermes -p coder gateway status` prints `standalone by config
|
||||
(gateway.standalone: true)` before the profile's own gateway state, and
|
||||
`hermes gateway status` (default) lists it as `standalone by config: coder`
|
||||
after the served set. `hermes gateway migrate --multiplex` leaves the profile
|
||||
alone and prints it as `Standalone by config (gateway.standalone: true), left
|
||||
alone`. The WhatsApp bridge and relay run in the profile's own gateway, as in
|
||||
any standalone gateway.
|
||||
|
||||
`--force` is not the path for this opt-out; it remains the escape for the two
|
||||
boundary cases the refusal names (a fleet split across UNIX users, a
|
||||
`HERMES_HOME` outside `profiles/`): it installs a real per-profile service, and
|
||||
that service (its `ExecStart` carries no `--force`) keeps starting normally
|
||||
afterwards.
|
||||
|
||||
### What changes when multiplexing is on
|
||||
|
||||
Multiplexing changes how a few things behave. None of these apply to a profile
|
||||
that runs a separate `--force` gateway on a blocked host.
|
||||
that opts out with `gateway.standalone: true` or runs a separate `--force`
|
||||
gateway on a blocked host.
|
||||
|
||||
#### 1. Secondary profiles must not start their own gateway
|
||||
|
||||
@@ -237,9 +294,11 @@ stray unit or plist that could only sit dead. Add the bot token and the running
|
||||
picks it up.
|
||||
|
||||
The multiplexer is the single inbound process; a second profile gateway would
|
||||
double-bind that profile's platforms. Pass `--force` (accepted by `run`, `start`,
|
||||
`install` and `restart`) only if you deliberately want a separate process for that
|
||||
profile (not recommended while the multiplexer is running). The cross-profile
|
||||
double-bind that profile's platforms. A profile that deliberately wants a
|
||||
separate process opts out with `gateway.standalone: true` (see
|
||||
[No new per-profile gateways](#no-new-per-profile-gateways)); pass `--force`
|
||||
(accepted by `run`, `start`, `install` and `restart`) only where a boundary
|
||||
blocks the fold. The cross-profile
|
||||
lifecycle wrapper script earlier on this page is therefore **not** used in
|
||||
multiplex mode — you only manage the default gateway.
|
||||
|
||||
@@ -279,6 +338,9 @@ no API server is enabled); it serves three kinds of profile-prefixed paths:
|
||||
secondary platform, and if **no** profile runs it a WARNING says the platform
|
||||
is not being served; `hermes gateway status --profile work` shows
|
||||
`whatsapp: not served under multiplex (shared ingress owned by default)`.
|
||||
The one exception is a profile that opted out with `gateway.standalone:
|
||||
true` — it runs its own WhatsApp bridge and relay in its own gateway, as any
|
||||
standalone gateway does.
|
||||
|
||||
Authentication follows the profile named in the URL. Unprefixed endpoints keep
|
||||
using the default listener's existing credentials.
|
||||
@@ -544,10 +606,14 @@ on the default profile).
|
||||
### Which profiles are served
|
||||
|
||||
`gateway.multiplex_profiles: true` serves the default profile plus **every**
|
||||
live named profile under `profiles/` — there is no per-profile opt-out list.
|
||||
live named profile under `profiles/`, except the ones that opted out with
|
||||
`gateway.standalone: true` in their own `config.yaml` — a standalone profile
|
||||
runs its own gateway and is not enumerated by the host (see
|
||||
[No new per-profile gateways](#no-new-per-profile-gateways)).
|
||||
(The former `gateway.multiplex_profile_allowlist` key is retired; a config
|
||||
migration removes it from `config.yaml`, and a profile you do not want served is
|
||||
archived or deleted instead — `hermes profile delete <name>`, or move the
|
||||
migration removes it from `config.yaml`, and a profile you do not want served
|
||||
but that has not opted out is archived or deleted instead —
|
||||
`hermes profile delete <name>`, or move the
|
||||
directory out of `profiles/`.) Deleted profiles leave a tombstone and are never
|
||||
enumerated; a profile whose directory is gone is never recreated by a served
|
||||
turn, the cron ticker or log routing.
|
||||
@@ -943,7 +1009,10 @@ hermes gateway migrate --multiplex # apply (asks for confirmation on
|
||||
|
||||
There is no `--standalone` reverse command: a per-profile fleet is not a
|
||||
supported target. A blocked fleet keeps running as it is, and each profile
|
||||
keeps `hermes -p <name> gateway install --force` as its stated path.
|
||||
keeps `hermes -p <name> gateway install --force` as its path — or opts out of
|
||||
the host gateway with `gateway.standalone: true` (see
|
||||
[No new per-profile gateways](#no-new-per-profile-gateways)), which
|
||||
`hermes gateway migrate --multiplex` respects.
|
||||
|
||||
### What `hermes update` does
|
||||
|
||||
@@ -978,8 +1047,9 @@ A standalone secondary behind any of these boundaries stops the automatic path:
|
||||
|
||||
In that case `hermes update` prints the boundary it found plus
|
||||
`hermes gateway migrate --multiplex`, and changes nothing — no unit is removed
|
||||
and the per-profile gateways keep running (`--force` remains their stated
|
||||
path). Collapsing such a fleet replaces a
|
||||
and the per-profile gateways keep running (`--force` remains their path where
|
||||
a boundary like these blocks the fold; a profile free of them opts out with
|
||||
`gateway.standalone: true`). Collapsing such a fleet replaces a
|
||||
kernel-enforced boundary (file ownership, `User=`) with in-process isolation,
|
||||
which is an operator's decision. The explicit command still makes it: the same
|
||||
findings appear as **notices** in `hermes gateway migrate --multiplex --dry-run`
|
||||
@@ -1034,7 +1104,7 @@ Older clones that still carry them are flagged by `hermes profile list`.
|
||||
| Blocker | Why | Fix |
|
||||
|---|---|---|
|
||||
| Two profiles configure the same platform credential (e.g. the same `TELEGRAM_BOT_TOKEN`) | Under one process a bot token can only be polled once; the multiplexer would park the duplicate and that profile's bot would go silent | Remove the token from the second profile, or keep it in `default` and route that profile's chats with [`profile_routes`](#routing-shared-bot-chats-to-profiles-profile_routes) |
|
||||
| A secondary profile enables a port-binding platform that has **no** `/p/<profile>/` ingress on the default listener | The multiplexer skips that whole profile (see [rule 2](#2-http-inbound-platforms-are-reached-via-a-pprofile-url-prefix)) | Disable the platform in that profile (`platforms.<name>.enabled: false`), or keep the profile on a standalone gateway with `hermes -p <name> gateway install --force` (a served profile's `install`/`start` refuse without it) |
|
||||
| A secondary profile enables a port-binding platform that has **no** `/p/<profile>/` ingress on the default listener | The multiplexer skips that whole profile (see [rule 2](#2-http-inbound-platforms-are-reached-via-a-pprofile-url-prefix)) | Disable the platform in that profile (`platforms.<name>.enabled: false`), or run the profile standalone: set `gateway.standalone: true` in its own `config.yaml` and wait for the host to rescan (at most 30 seconds), or send its `rescan-profiles` control verb. Use `hermes -p <name> gateway install --force` only where a boundary blocks the fold. |
|
||||
|
||||
The credential check reuses the gateway's own conflict detection, so its verdict
|
||||
matches what the multiplexer does at startup. Which port-binding platforms have
|
||||
|
||||
Reference in New Issue
Block a user