summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAdam Malczewski <[email protected]>2026-05-29 12:23:30 +0900
committerAdam Malczewski <[email protected]>2026-05-29 12:23:30 +0900
commit0954c6520878e073c7822fc4a8f4a752474f5d7a (patch)
treeb19012f89ccbb07bf3180612a6cfef7077618d6b
parentd6609efd4e14101e77fb35a98ce597a32816862d (diff)
downloaddispatch-0954c6520878e073c7822fc4a8f4a752474f5d7a.tar.gz
dispatch-0954c6520878e073c7822fc4a8f4a752474f5d7a.zip
fix(packaging): convert dispatch-systemd from user units to system template units (User=%i)
The per-user systemd manager ([email protected]) fails to start on WSL (kernel 6.6.87.2, microsoft/WSL#13186 — 'Failed to spawn executor: Device or resource busy'), which breaks pacman's 30-systemd-daemon-reload-user.hook on install. Changes: - New [email protected] + [email protected] system template units with User=%i (run as the named instance user) - Remove old user-scope dispatch-api.service / dispatch-frontend.service - Install to /usr/lib/systemd/system/ instead of .../systemd/user/ - Update PKGBUILD, .install hints, and bin/service to use sudo systemctl dispatch-api@<user>
-rwxr-xr-xbin/service44
-rw-r--r--packaging/PKGBUILD18
-rw-r--r--packaging/dispatch-api.service15
-rw-r--r--packaging/[email protected]21
-rw-r--r--packaging/dispatch-frontend.service16
-rw-r--r--packaging/[email protected]22
-rw-r--r--packaging/dispatch-systemd.install19
-rw-r--r--packaging/dispatch.install6
8 files changed, 99 insertions, 62 deletions
diff --git a/bin/service b/bin/service
index eaa63eb..62471b9 100755
--- a/bin/service
+++ b/bin/service
@@ -4,6 +4,12 @@ set -euo pipefail
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
PROJECT_DIR="$(dirname "$SCRIPT_DIR")"
+# Dispatch runs as system service instances keyed on the *invoking* user, so
+# `bin/service start` brings the services up running as you (e.g. dispatch-api@tradam).
+RUN_USER="$(id -un)"
+API_UNIT="dispatch-api@${RUN_USER}"
+FRONTEND_UNIT="dispatch-frontend@${RUN_USER}"
+
cmd="${1:-help}"
shift 2>/dev/null || true
@@ -12,16 +18,20 @@ usage() {
Usage: bin/service <command>
Commands:
- install Install the dispatch packages (systemd user units +
+ install Install the dispatch packages (systemd system unit templates +
application files in /opt/dispatch).
- start Start dispatch-api and dispatch-frontend.
+ start Start dispatch-api and dispatch-frontend as ${RUN_USER}.
If already running, restart instead.
Prints the frontend URL when ready.
stop Stop dispatch-api and dispatch-frontend.
status Show status of both services.
logs Tail journal output for both services.
-After install, configure /etc/dispatch/dispatch-api.conf before starting.
+Services run as system instances for the current user:
+ ${API_UNIT}
+ ${FRONTEND_UNIT}
+Start/stop use sudo (system manager). After install, configure
+/etc/dispatch/dispatch-api.conf before starting.
EOF
}
@@ -33,14 +43,14 @@ install() {
echo "==> Installing..."
"$PROJECT_DIR/bin/install-pkg"
- systemctl --user daemon-reload
+ sudo systemctl daemon-reload
echo ""
echo "==> Installed. Edit /etc/dispatch/dispatch-api.conf, then run:"
echo " bin/service start"
}
have_units() {
- systemctl --user cat dispatch-api.service &>/dev/null
+ systemctl cat [email protected] &>/dev/null
}
start() {
@@ -49,29 +59,39 @@ start() {
return 1
fi
local api_active frontend_active
- api_active=$(systemctl --user is-active dispatch-api 2>/dev/null || echo "inactive")
- frontend_active=$(systemctl --user is-active dispatch-frontend 2>/dev/null || echo "inactive")
+ api_active=$(systemctl is-active "$API_UNIT" 2>/dev/null || echo "inactive")
+ frontend_active=$(systemctl is-active "$FRONTEND_UNIT" 2>/dev/null || echo "inactive")
if [ "$api_active" = "active" ] || [ "$frontend_active" = "active" ]; then
echo "==> Services already running (api=$api_active frontend=$frontend_active) — restarting"
- systemctl --user restart dispatch-api dispatch-frontend
+ sudo systemctl restart "$API_UNIT" "$FRONTEND_UNIT"
+ echo "dispatch-api + dispatch-frontend restarted (as ${RUN_USER})"
else
- systemctl --user start dispatch-api dispatch-frontend
+ sudo systemctl start "$API_UNIT" "$FRONTEND_UNIT"
+ echo "dispatch-api + dispatch-frontend started (as ${RUN_USER})"
fi
- echo "dispatch-api + dispatch-frontend $( [ "$api_active" = "active" ] || [ "$frontend_active" = "active" ] && echo restarted || echo started )"
echo " → http://localhost:18391"
}
+stop() {
+ if ! have_units; then
+ echo "dispatch services not installed."
+ return 1
+ fi
+ sudo systemctl stop "$API_UNIT" "$FRONTEND_UNIT"
+ echo "dispatch-api + dispatch-frontend stopped"
+}
+
status() {
if ! have_units; then
echo "dispatch services not installed."
return 1
fi
- systemctl --user status dispatch-api dispatch-frontend --no-pager 2>/dev/null || true
+ systemctl status "$API_UNIT" "$FRONTEND_UNIT" --no-pager 2>/dev/null || true
}
logs() {
- journalctl --user -u dispatch-api -u dispatch-frontend -f "$@"
+ sudo journalctl -u "$API_UNIT" -u "$FRONTEND_UNIT" -f "$@"
}
case "$cmd" in
diff --git a/packaging/PKGBUILD b/packaging/PKGBUILD
index a514eb5..6aa66cc 100644
--- a/packaging/PKGBUILD
+++ b/packaging/PKGBUILD
@@ -2,7 +2,7 @@
#
# Split package: builds the base application once and produces three packages:
# dispatch — application files + CLI wrappers + env configs
-# dispatch-systemd — systemd user units for dispatch-api / dispatch-frontend
+# dispatch-systemd — systemd system units (run as a given user: dispatch-api@<user>)
# dispatch-s6 — s6 service definitions for dispatch-api / dispatch-frontend
#
# The Electron desktop wrapper lives in a separate PKGBUILD at packaging/electron/.
@@ -129,21 +129,25 @@ package_dispatch() {
}
# ----------------------------------------------------------------------------
-# dispatch-systemd — systemd user unit files
+# dispatch-systemd — systemd system unit templates (run as a chosen user)
+#
+# These are *system* units (managed by PID 1), not user units, so they do not
+# depend on a per-user `[email protected]` manager. Each is a template keyed on
+# the username: `dispatch-api@tradam` runs as the `tradam` user via User=%i.
# ----------------------------------------------------------------------------
package_dispatch-systemd() {
- pkgdesc='Systemd user units for the Dispatch API and Frontend services'
+ pkgdesc='Systemd system unit templates for the Dispatch API and Frontend services (run as dispatch-api@<user>)'
depends=("dispatch=${pkgver}" 'systemd')
conflicts=('dispatch-s6')
install=dispatch-systemd.install
install -Dm644 \
- "${_packagingdir}/dispatch-api.service" \
- "${pkgdir}/usr/lib/systemd/user/dispatch-api.service"
+ "${_packagingdir}/[email protected]" \
+ "${pkgdir}/usr/lib/systemd/system/[email protected]"
install -Dm644 \
- "${_packagingdir}/dispatch-frontend.service" \
- "${pkgdir}/usr/lib/systemd/user/dispatch-frontend.service"
+ "${_packagingdir}/[email protected]" \
+ "${pkgdir}/usr/lib/systemd/system/[email protected]"
}
# ----------------------------------------------------------------------------
diff --git a/packaging/dispatch-api.service b/packaging/dispatch-api.service
deleted file mode 100644
index 120d460..0000000
--- a/packaging/dispatch-api.service
+++ /dev/null
@@ -1,15 +0,0 @@
-[Unit]
-Description=Dispatch API Backend
-
-[Service]
-Type=simple
-WorkingDirectory=/opt/dispatch
-ExecStart=/usr/bin/bun packages/api/src/index.ts
-EnvironmentFile=-/etc/dispatch/dispatch-api.conf
-Restart=on-failure
-RestartSec=5
-StandardOutput=journal
-StandardError=journal
-
-[Install]
-WantedBy=default.target
diff --git a/packaging/[email protected] b/packaging/[email protected]
new file mode 100644
index 0000000..3449fcb
--- /dev/null
+++ b/packaging/[email protected]
@@ -0,0 +1,21 @@
+# Dispatch API — system service template.
+# Runs under the system manager (PID 1) but drops privileges to the user named
+# in the instance: `dispatch-api@tradam` runs as the `tradam` user.
+#
+# Enable/start:
+# sudo systemctl enable --now dispatch-api@<user>
+[Unit]
+Description=Dispatch API Backend (running as %i)
+After=network.target
+
+[Service]
+Type=simple
+User=%i
+WorkingDirectory=/opt/dispatch
+ExecStart=/usr/bin/bun packages/api/src/index.ts
+EnvironmentFile=-/etc/dispatch/dispatch-api.conf
+Restart=on-failure
+RestartSec=5
+
+[Install]
+WantedBy=multi-user.target
diff --git a/packaging/dispatch-frontend.service b/packaging/dispatch-frontend.service
deleted file mode 100644
index 4aca1a3..0000000
--- a/packaging/dispatch-frontend.service
+++ /dev/null
@@ -1,16 +0,0 @@
-[Unit]
-Description=Dispatch Frontend (static file server)
-After=dispatch-api.service
-
-[Service]
-Type=simple
-WorkingDirectory=/opt/dispatch
-ExecStart=/usr/bin/bun packages/frontend/serve.ts
-EnvironmentFile=-/etc/dispatch/dispatch-frontend.conf
-Restart=on-failure
-RestartSec=5
-StandardOutput=journal
-StandardError=journal
-
-[Install]
-WantedBy=default.target
diff --git a/packaging/[email protected] b/packaging/[email protected]
new file mode 100644
index 0000000..6f35cc1
--- /dev/null
+++ b/packaging/[email protected]
@@ -0,0 +1,22 @@
+# Dispatch Frontend — system service template.
+# Runs under the system manager (PID 1) but drops privileges to the user named
+# in the instance: `dispatch-frontend@tradam` runs as the `tradam` user.
+# Tied to the matching API instance for the same user.
+#
+# Enable/start:
+# sudo systemctl enable --now dispatch-frontend@<user>
+[Unit]
+Description=Dispatch Frontend (static file server, running as %i)
+After=dispatch-api@%i.service
+
+[Service]
+Type=simple
+User=%i
+WorkingDirectory=/opt/dispatch
+ExecStart=/usr/bin/bun packages/frontend/serve.ts
+EnvironmentFile=-/etc/dispatch/dispatch-frontend.conf
+Restart=on-failure
+RestartSec=5
+
+[Install]
+WantedBy=multi-user.target
diff --git a/packaging/dispatch-systemd.install b/packaging/dispatch-systemd.install
index 3bd29be..5ebf261 100644
--- a/packaging/dispatch-systemd.install
+++ b/packaging/dispatch-systemd.install
@@ -1,24 +1,25 @@
post_install() {
echo ""
- echo "==> Dispatch systemd user units installed."
- echo " Enable and start:"
- echo " systemctl --user daemon-reload"
- echo " systemctl --user enable --now dispatch-api dispatch-frontend"
+ echo "==> Dispatch systemd system unit templates installed."
+ echo " These run as the user named in the instance (replace <user>)."
+ echo " Enable and start (e.g. for user 'tradam'):"
+ echo " sudo systemctl daemon-reload"
+ echo " sudo systemctl enable --now dispatch-api@<user> dispatch-frontend@<user>"
echo ""
}
post_upgrade() {
echo ""
echo "==> Dispatch systemd units upgraded."
- echo " Reload and restart:"
- echo " systemctl --user daemon-reload"
- echo " systemctl --user restart dispatch-api dispatch-frontend"
+ echo " Reload and restart your instances (replace <user>):"
+ echo " sudo systemctl daemon-reload"
+ echo " sudo systemctl restart dispatch-api@<user> dispatch-frontend@<user>"
echo ""
}
pre_remove() {
echo ""
- echo "==> Stop dispatch services before removal:"
- echo " systemctl --user disable --now dispatch-api dispatch-frontend"
+ echo "==> Stop dispatch services before removal (replace <user>):"
+ echo " sudo systemctl disable --now dispatch-api@<user> dispatch-frontend@<user>"
echo ""
}
diff --git a/packaging/dispatch.install b/packaging/dispatch.install
index 76837f5..75b36cc 100644
--- a/packaging/dispatch.install
+++ b/packaging/dispatch.install
@@ -11,7 +11,7 @@ post_install() {
echo " dispatch-frontend # static frontend (port 18391 by default)"
echo ""
echo " To run as a service, install one of:"
- echo " pacman -S dispatch-systemd # systemd user services"
+ echo " pacman -S dispatch-systemd # systemd system services (run as your user)"
echo " pacman -S dispatch-s6 # s6 services (Artix)"
echo ""
echo " For the Electron desktop wrapper:"
@@ -22,8 +22,8 @@ post_install() {
post_upgrade() {
echo ""
echo "==> Dispatch (base) upgraded."
- echo " If you use dispatch-systemd, restart the units:"
- echo " systemctl --user restart dispatch-api dispatch-frontend"
+ echo " If you use dispatch-systemd, restart the units (replace <user>):"
+ echo " sudo systemctl restart dispatch-api@<user> dispatch-frontend@<user>"
echo " If you use dispatch-s6, restart the services:"
echo " s6-svc -r /run/service/dispatch-api"
echo " s6-svc -r /run/service/dispatch-frontend"