feat(sidecar): start as a real Windows service
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 2m22s
All checks were successful
PR Checks / rust-gates (pull_request) Successful in 2m22s
`sc.exe start RunicGatewayLink` failed with 1053 on every Windows install:
"a timeout was reached (30000 milliseconds) while waiting for the service to
connect", with SERVICE_EXIT_CODE 0. Nothing had crashed. The sidecar was a
plain console program, and the Windows service control manager only supervises
a process that calls StartServiceCtrlDispatcher and identifies itself within
~30 seconds.
The installer's design assumed symmetry with systemd, which supervises any
foreground process. Windows has no equivalent: it is a service-aware binary or
a shim, and a shim was already rejected as a third binary to keep current.
Split the entry point so the platform only owns starting and stopping:
systemd --> main --> unix::run ---------------+
+--> app::run
SCM ------> main --> windows::run --> ServiceMain
\-> console fallback
- app.rs is the whole sidecar, unchanged and shared. No #[cfg] on the data path.
- windows.rs speaks the SCM handshake. The dispatcher is tried first and failing
is expected: ERROR_FAILED_SERVICE_CONTROLLER_CONNECT (1063) means "not started
by the SCM" and falls through to a normal foreground run, so one binary does
both with no --service flag to forget.
- Running is reported only once the shard port is bound and the store is open, so
a bad config fails the start instead of flapping Running -> Stopped, and a
failed run leaves a nonzero SERVICE_EXIT_CODE instead of the misleading 0.
- A service has no stdout, so service mode logs to uo-link-sidecar.log.<date>
beside its config, rolled daily, seven kept.
- unix.rs additionally handles SIGTERM, which is what systemctl stop sends and
which previously took the default disposition mid-write.
The Windows crates are declared under [target.'cfg(windows)'.dependencies].
Verified: a Linux build in rust:1-slim-bookworm succeeds and resolves neither
windows-service nor tracing-appender.
Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
23
README.md
23
README.md
@@ -48,6 +48,29 @@ to read the token back; it is not meant to be scraped from the log.
|
||||
uo-link-sidecar --print-config --config /etc/runicgateway/sidecar.toml
|
||||
```
|
||||
|
||||
### Running as a service
|
||||
|
||||
The same binary runs in the foreground and as a system service — there is no `--service` flag to
|
||||
remember, because the process can tell how it was started.
|
||||
|
||||
- **Linux/systemd** supervises any foreground process, so the unit just runs the binary. `SIGTERM`
|
||||
(what `systemctl stop` sends) and `SIGINT` both unwind it cleanly; logs go to the journal.
|
||||
- **Windows** cannot. The service control manager only supervises a process that connects back to
|
||||
it within ~30 seconds via `StartServiceCtrlDispatcher`; a plain console program registered with
|
||||
`sc.exe create` is killed with **error 1053** despite running perfectly. So on Windows the sidecar
|
||||
speaks that handshake: started by the SCM it runs as a service, started from a shell the connect
|
||||
fails with `ERROR_FAILED_SERVICE_CONTROLLER_CONNECT` and it falls through to an ordinary
|
||||
foreground run. It reports `Running` only once the shard port is bound and the store is open, and
|
||||
— having no console — logs to `uo-link-sidecar.<date>.log` beside its config, rolled daily.
|
||||
|
||||
Only the starting and stopping is platform-specific: `src/app.rs` is the entire sidecar and is
|
||||
shared, while `src/windows.rs` and `src/unix.rs` do nothing but start it and tell it when to stop.
|
||||
The Windows crates are declared under `[target.'cfg(windows)'.dependencies]`, so Cargo neither
|
||||
resolves nor builds them for a Linux target.
|
||||
|
||||
Registering the service is the installer's job; to do it by hand see
|
||||
[INSTALL.md Appendix A4](https://gitea.whitlocktech.com/RunicGateway/docs/src/branch/main/installer/INSTALL.md).
|
||||
|
||||
`.gitea/workflows/release.yml` cross-compiles Linux + Windows binaries and cuts a Gitea release on
|
||||
every merge to `main` (conventional-commit versioning). See [`sidecar/README.md`](sidecar/README.md)
|
||||
for configuration and the wire protocol.
|
||||
|
||||
Reference in New Issue
Block a user