Deployment: from "it runs" to "it can be hosted"
Deploying a XServer application is as simple as "copy the directory" — the hard part is all in servicing: boot autostart, crash restart, and the external backstop for graceful shutdown. This chapter includes home's real production scripts.
Overview
42.1 Intro
Deploying a XServer application involves no dependency list, no environment prep, no install steps — chapter 2 folded all that away. Only three ops questions remain: where to put it (directory planning), how to keep it resident (the service manager), and how to stop it gracefully (graceful shutdown + an external timeout). This chapter handles each in turn.
42.2 Deliverables & runtime layout
/opt/www/ /* deploy root = executable dir = config dir */
├── xs /* the only binary (compiler/SDK/runtime inside) */
├── xs.json /* master config: services + every vhost */
├── host/default/... /* the site farm (ch. 20's layout) */
├── host/xxdevs/...
├── tools/ dev/ /* ops helpers and dev backups */
└── (nothing else — no other dependencies)
- Versioning: the whole directory is one unit — rollback = swapping back the previous directory copy (xs.exe and sources/config always share a version)
- Update paths: structural change = copy into a new directory and restart; everyday updates = overwrite script files + reload (minute-level change discipline, ch. 31)
- Data isolation: db/ lives inside the site directory — backup strategy works per directory
42.3 Service management
home production's real start script (verbatim from the repository):
#!/bin/sh
case "${1}" in
start)
cd /opt/www
sudo nohup /opt/www/xs /opt/www/xs.json &
;;
stop)
sudo pkill -9 -f /opt/www/xs /* note: -9 hard kill */
;;
restart)
sudo pkill -9 -f /opt/www/xs
cd /opt/www; sudo nohup /opt/www/xs /opt/www/xs.json &
;;
esac
What just happened: this script shows the minimal viable form and exposes one improvement — pkill -9 is a hard kill that skips graceful shutdown (ch. 06's five phases). The recommended form is a systemd unit making polite-first the default:
[Unit]
Description=xs application server
After=network.target
[Service]
Type=simple
WorkingDirectory=/opt/www
ExecStart=/opt/www/xs /opt/www/xs.json
/* graceful shutdown: SIGTERM with ample time, SIGKILL only on timeout */
KillSignal=SIGTERM
TimeoutStopSec=120
Restart=on-failure
RestartSec=3
/* output into journald; in-app level logging via xrtLogger */
StandardOutput=journal
[Install]
WantedBy=multi-user.target
The Windows counterpart: a service wrapper (or a scheduled task + net stop delivering process-group signals via CTRL_BREAK — that's what test.bat's wingrp tool does).
42.4 Shutdown discipline
- Inside: SIGTERM/Ctrl+C → the five-phase graceful shutdown (ch. 06) — no forced teardown; long connections wait to the end
- Outside: the service manager provides the backstop — systemd's TimeoutStopSec, supervisor's stopwaitsecs. How long? Slightly beyond your longest legitimate request (e.g. the file-download ceiling + buffer)
- Order: the rolling-update rhythm is "new instance ready → switch traffic → SIGTERM the old instance → wait for drain → backstop hard kill"
42.5 Contract
- Directory: deploy root = exe = config; the whole directory is versioned; rollback is a directory swap.
- Service: residency goes to the service manager; Restart=on-failure is the crash backstop.
- Shutdown: internal grace + external timeout — neither alone suffices.
Common mistakes
- Symptom
- Every "release" drops all connections; users read it as an outage.
- Cause
- -9 skips the graceful path — ServiceUnit never runs, in-flight requests are cut in half. SIGTERM is the routine method; -9 belongs only to the backstop.
- Symptom
- On some machines "xs.json / static root not found".
- Cause
- XServer looks for config in the executable's directory by default (ch. 02) — WorkingDirectory only affects CWD-relative operations. Keep passing the full path to xs.json or standardize the layout; don't rely on CWD.
Exercises
Register your application as a system service with 42.3's unit.
With load testing and a large download in flight, issue stop and tune TimeoutStopSec to the minimum with zero failures.
Implement a blue-green release script: dual directories + symlink switch + old-instance drain.
Summary
| Point | Conclusion |
|---|---|
| Delivery | deploy root = exe = config; whole directories versioned |
| Residency | systemd: Restart backstops crashes, journal collects logs |
| Shutdown | SIGTERM grace + TimeoutStopSec external backstop |
| Release | daily reload / structural change via directory restart / blue-green rolling |
- xrt reference · signal — signal-handling platform differences (the host handles them for you)