phpbotscout serve¶
Runs phpbotscout as a long-lived process. It supervises two things: the Discord gateway that watches the allowlisted channels, and the scheduled refresh that keeps the knowledge index current.
Usage¶
Managed services¶
Services register with controls rather than being
hand-rolled goroutines, so startup ordering, health and shutdown are the
supervisor's job and not each service's.
| Service | What it does | Restart policy |
|---|---|---|
discord-gateway/<guild> |
Connects the gateway and reads the allowlisted channels. One per configured guild. | Backs off: 10 restarts, 2s initial, 5m maximum |
index-refresher |
Re-reads the corpus on a timer. | None |
The gateway backs off because a gateway that cannot connect will not connect
harder for being asked more often, and Discord rate-limits identify. The
refresher has no policy because its Start cannot fail, and the failure it does
have — a forge that will not answer — is not fixed by restarting anything.
The scheduled refresh¶
The refresher calls the same Refresh that
index refresh calls. One code path, so the scheduled and
manual routes cannot drift into disagreeing about what is indexed.
It refreshes once at startup and then on every tick of
index.refresh_interval. Refreshing at startup
rather than waiting a full interval means a daemon restarted after downtime
notices the world moved on promptly. Startup does not wait for that first
refresh — indexing the corpus takes minutes, and a supervisor waiting on it
would report the daemon as failing to come up while it was working correctly.
Two refreshes never overlap. If one is still running when the next tick arrives, that tick is skipped rather than queued: two concurrent runs would write the same documents in parallel.
Failure is degradation, not an outage¶
A refresh that fails is counted and logged, and the daemon keeps running.
- Liveness always passes. A restart would not reach an unreachable forge.
- Readiness does not fail on a stale index. Answering from what is already indexed — with a caveat — beats not answering, and taking the bot out of service would fix nothing. This is the same judgement the gateway makes about a reconnect that lost events.
Staleness is reported through index status, which is where
an operator can act on it.
A source that fails while the rest of the run succeeds is logged by name with its reason. The run itself reports success, so that log line is the only signal that part of the corpus went unindexed.
Shutdown¶
Stop waits for a refresh already in flight. Returning immediately would let
the process exit between writing a document and recording the commit it came
from, leaving the index claiming to hold content it does not. The wait is
bounded by the shutdown deadline; past it the refresh is cancelled and its
transaction rolls back.
Startup refuses a bad configuration¶
Building the forge provider makes no network call, so it can only fail on a configuration an operator can fix in seconds — a malformed API URL, an index path that cannot be opened, a provider that cannot enumerate a namespace. Those fail startup, in keeping with how the gateway's own configuration is treated.
A forge that is merely unreachable is a different thing entirely. That is not known at startup, surfaces later as a failed refresh, and degrades rather than stopping the daemon.
Health endpoints¶
serve mounts /healthz, /livez and /readyz on the
health listener, which binds 127.0.0.1:8081 by
default. Wildcard binds are refused.
Flags¶
serve defines no flags of its own.
| Name | Description | Default |
|---|---|---|
-h, --help |
Help for serve. |
false |
Global flags (--config, --debug, --output, --ci) are inherited from the
root command.