Chapter 42 / 51
Volume 5 · Extensions, Ops & Projects

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

Positioning: the last mile from an ops viewpoint. ch. 06's "shutdown has no forced-teardown timeout" is redeemed here as a service-manager configuration item.

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

home's production layout (real shape)source: home repository /opt/www
/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):

xs.service (home's original, SysV style)production samplesource: home/xs.service
#!/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:

Recommended: xs.service (systemd unit)
[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

Using kill -9 as the routine method
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.
Assuming paths can be written freely once WorkingDirectory is set
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

BasicGoing live with systemd

Register your application as a system service with 42.3's unit.

Acceptance: start/stop/status/boot-autostart all work; the stop log shows the full five phases.
AdvancedMeasuring the shutdown window

With load testing and a large download in flight, issue stop and tune TimeoutStopSec to the minimum with zero failures.

Acceptance: state your business's recommended shutdown window with the reasoning.
ChallengeBlue-green directories

Implement a blue-green release script: dual directories + symlink switch + old-instance drain.

Acceptance: 100% availability end to end; rollback in one command.

Summary

PointConclusion
Deliverydeploy root = exe = config; whole directories versioned
Residencysystemd: Restart backstops crashes, journal collects logs
ShutdownSIGTERM grace + TimeoutStopSec external backstop
Releasedaily reload / structural change via directory restart / blue-green rolling
API references in this chapter
xrt further reading