]> mop.ddnsfree.com - git repositories - brisk.git/commitdiff
write a systemd unit for the daemon instead of the sysv script
authorMatteo Nastasi <nastasi@alternativeoutput.it>
Wed, 7 Oct 2026 09:32:33 +0000 (09:32 +0000)
committerMatteo Nastasi <nastasi@alternativeoutput.it>
Wed, 7 Oct 2026 09:32:33 +0000 (09:32 +0000)
"INSTALL.sh system" wrote a script into /etc/init.d. On debian 13 that
script is never run: the sysv compatibility generator of systemd is gone,
so nothing turns it into a service and nothing starts it at boot.

Where systemd is in charge the action now writes <name>.service in Etc,
beside the nginx and nftables files, and leaves /etc/init.d alone; without
systemd it installs the sysv script exactly as before. The unit is only
written, and the run prints the three commands that install it, as for the
other generated files.

What the unit had to get right, both found by running the daemon:

  - -d. Without it the daemon keeps stdin in its select set, and stdin
    being /dev/null under systemd it reads EOF at once and exits with 22
    (sac-a-push.phh, the branch that returns 22). The sysv script got away
    without it because screen gave the daemon a tty.

  - KillSignal stays SIGTERM. On SIGTERM the daemon serializes the room
    into <legal_path>/brisk-crystal.data and exits 0, and the next start
    reads it back, so a stop and a start keep the games. SIGINT exits with
    1 and saves nothing.

Restart=on-failure, so a stop asked for stays stopped while a crash comes
back up; TimeoutStopSec=15, measured against the 56ms an empty room takes
to serialize; ExecReload sends SIGHUP, which the daemon already treats as
a reload; WorkingDirectory because the daemon reaches its own files by
relative paths. The screen session and the shell loop that respawned the
daemon are both gone, and its output goes to the journal, which the unit
says how to silence.

ngx_put is now gen_put: it is no longer only for nginx files.

Checked in a container with systemd: the unit passes systemd-analyze
verify, the service starts and binds the eleven ports, systemctl reload
reaches the daemon without changing its pid, systemctl stop exits 0 in
50ms leaving brisk-crystal.data behind, the next start logs "ROOM FROM
FILE", and a SIGKILL on the main process brings it back up (NRestarts=1).

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
INSTALL.sh
WARNING.txt
bin/brisk-init.sh

index 10fd27f13c20dbe97b4c857a93e85e72c9172b47..685a604f040e2d8ec6be037fcdd3824f6fa9f2e0 100755 (executable)
@@ -135,7 +135,7 @@ function searchetc() {
 # Put a freshly generated file in place: left alone when nothing changed,
 # otherwise the previous version is kept as .old, because these files are
 # also the ones somebody may have touched by hand.
-function ngx_put() {
+function gen_put() {
     local tmp dst
     tmp="$1"
     dst="$2"
@@ -196,6 +196,78 @@ function fpm_front_ports() {
     done | sort -un
 }
 
+# Whether this machine is run by systemd. A /etc/init.d script is of no use
+# where it is: debian 13 dropped the sysv compatibility generator, so the
+# script is never turned into a service and nothing starts it at boot.
+function has_systemd() {
+    [ -d /run/systemd/system ] && command -v systemctl >/dev/null 2>&1
+}
+
+# The systemd unit of the daemon, written in Etc as <name>.service, to be
+# copied by hand into /etc/systemd/system/. It replaces bin/brisk-init.sh,
+# which wrapped the daemon in a screen session and respawned it with a shell
+# loop: Restart= is that loop, and the log goes to the journal instead of
+# staying inside a screen nobody attaches to.
+function systemd_unit_gen() {
+    local name unit_f tmp
+    local pfx_ws
+
+    name="$(inst_name)"
+    unit_f="$etc_path/${name}.service"
+    pfx_ws="$(echo "$web_path" | sed 's:/*$::')"
+
+    tmp="$(mktemp)"
+    cat > "$tmp" <<EOF
+# brisk ${name} - systemd unit of the brisk-spush daemon.
+# Generated by INSTALL.sh, do not edit: run "INSTALL.sh system" again instead.
+#   cp ${unit_f} /etc/systemd/system/${name}.service
+#   systemctl daemon-reload
+#   systemctl enable --now ${name}
+
+[Unit]
+Description=Brisk daemon (${name})
+# postgresql.service in After= is simply ignored when the database is on
+# another machine or is not postgres
+After=network-online.target postgresql.service
+Wants=network-online.target
+
+[Service]
+Type=simple
+User=${sys_user}
+# the daemon reaches its own files by relative paths ("./brisk-spush.phh",
+# and "../" for Obj/), so it has to start from spush/
+WorkingDirectory=${pfx_ws}/spush
+# -d is NOT optional: without it the daemon keeps stdin in its select set,
+# and stdin being /dev/null here it reads EOF at once and exits with 22.
+# brisk-init.sh got away without it because screen gave it a tty.
+ExecStart=${pfx_ws}/spush/brisk-spush.php -d
+ExecReload=/bin/kill -HUP \$MAINPID
+# SIGTERM makes the daemon serialize the room into
+# ${legal_path}/brisk-crystal.data and exit 0, and the next start picks the
+# room up from there. SIGINT would exit without saving anything, so the
+# signal of the stop has to stay SIGTERM.
+KillSignal=SIGTERM
+# measured at 56ms on an empty room; the room of a busy evening takes longer
+# to serialize, and after this systemd resorts to SIGKILL, which saves nothing
+TimeoutStopSec=15
+# a deliberate stop exits 0 and stays stopped; a crash, or a SIGKILL, comes
+# back up
+Restart=on-failure
+RestartSec=1
+
+[Install]
+WantedBy=multi-user.target
+
+# The daemon writes a line to stdout and one to stderr every four seconds,
+# and from here they go to the journal. To keep them out of it, add
+#   StandardOutput=null
+#   StandardError=null
+# to [Service], and the loss is only those two lines: what matters, from the
+# refused starts to the failed admin checks, is on stderr as well.
+EOF
+    gen_put "$tmp" "$unit_f"
+}
+
 # The nftables rules of the daemon machine of a split installation, written
 # in Etc as <name>.nft, to be copied by hand into /etc/nftables.d/. Over tcp
 # the daemon believes X-Real-Ip, which the bans are built on, and its control
@@ -260,7 +332,7 @@ function nft_conf_gen() {
         echo "    }"
         echo "}"
     } > "$tmp"
-    ngx_put "$tmp" "$nft_f"
+    gen_put "$tmp" "$nft_f"
     if [ -n "$fpm_ports" ]; then
         echo "  php-fpm serves the front from here (port ${fpm_ports}): included"
     else
@@ -341,7 +413,7 @@ function nginx_conf_gen() {
         fi
         echo "}"
     } > "$tmp"
-    ngx_put "$tmp" "$http_f"
+    gen_put "$tmp" "$http_f"
 
     # --- the nine daemon urls ---
     tmp="$(mktemp)"
@@ -375,7 +447,7 @@ proxy_set_header        Connection        \$${var}_connection_upgrade;
 # be down together with the daemon
 error_page              502 503 504 ${pfx}/daemon-down.html;
 EOF
-    ngx_put "$tmp" "$inc_f"
+    gen_put "$tmp" "$inc_f"
 
     # --- inside the server {} ---
     tmp="$(mktemp)"
@@ -447,7 +519,7 @@ EOF
             done
         fi
     } > "$tmp"
-    ngx_put "$tmp" "$srv_f"
+    gen_put "$tmp" "$srv_f"
 
     if [ -n "$ngx_ver" ]; then
         echo "  written for the nginx found here, $ngx_ver: check it with nginx -t"
@@ -649,7 +721,35 @@ if [ "$action" = "system" ]; then
     echo "private path: [$legal_path]"
     echo "system user:  [$sys_user]"
     echo
+    if has_systemd; then
+        echo "init system:  [systemd] -> a unit, written in Etc"
+    else
+        echo "init system:  [no systemd] -> the sysv script, in /etc/init.d"
+    fi
+    echo
     read -p "press enter to continue" sure
+
+    if has_systemd; then
+        # Etc is where the other generated files go; this action runs before
+        # the pre-check that looks it up, so it is looked up here.
+        etc_path="$(searchetc "$(dirname "$web_path")" Etc)"
+        if [ $? -ne 0 ]; then
+            echo "Etc directory not found above $(dirname "$web_path")"
+            exit 1
+        fi
+        echo "systemd unit:"
+        systemd_unit_gen
+        echo
+        echo "... DONE."
+        echo "DON'T FORGET: the unit is only written, not installed. Copy it, then:"
+        echo
+        echo "  su -c 'cp $etc_path/${scrname}.service /etc/systemd/system/'"
+        echo "  su -c 'systemctl daemon-reload'"
+        echo "  su -c 'systemctl enable --now ${scrname}'"
+        echo
+        exit 0
+    fi
+
     cp bin/brisk-init.sh brisk-init.sh.wrk
     sed -i "s@^BPATH=.*@BPATH=\"${web_path}\"@g;s@^PPATH=.*@PPATH=\"${legal_path}\"@g;s@^SSUFF=.*@SSUFF=\"${scrname}\"@g;s@^BUSER=.*@BUSER=\"${sys_user}\"@g" brisk-init.sh.wrk
 
index 63f9c7cfcc9ae5cd4ad156a698345dd8d506a364..6de382fd510a5ac1d482156d9a67e21612eca1fd 100644 (file)
@@ -95,3 +95,37 @@ NOTES on the shape of the ProxyPass lines (checked on apache 2.4.68):
 
 Everything that is not in this list (the static pages, admin.php,
 usermgmt.php, the .css and the .js) is still served by apache.
+
+
+==== 3. STARTING THE DAEMON: SYSTEMD ====
+
+"INSTALL.sh system" used to write a sysv script into /etc/init.d. On debian
+13 that script is never run: the sysv compatibility generator of systemd is
+gone, so nothing turns it into a service and nothing starts it at boot.
+
+Where systemd is in charge, the action now writes a unit in Etc instead,
+<name>.service beside the other generated files, and leaves /etc/init.d
+alone. It is only written: copy it, reload, enable.
+
+    su -c 'cp <Etc>/brisk.service /etc/systemd/system/'
+    su -c 'systemctl daemon-reload'
+    su -c 'systemctl enable --now brisk'
+
+Without systemd nothing changes: the sysv script is installed as before.
+
+Two things the unit does that are easy to get wrong by hand:
+
+  - brisk-spush.php is started with -d. Without it the daemon keeps stdin
+    in its select set, and stdin being /dev/null under systemd it reads EOF
+    at once and exits with 22. The sysv script got away without it because
+    it wrapped the daemon in a screen session, which gave it a tty.
+
+  - the signal of the stop stays SIGTERM. On SIGTERM the daemon serializes
+    the room into <legal_path>/brisk-crystal.data and exits 0, and the next
+    start picks the room up from there, so a stop and a start do not throw
+    the games away. SIGINT exits without saving anything.
+
+Restart=on-failure, not always: a stop asked for exits 0 and stays stopped,
+while a crash or a SIGKILL comes back up. The screen session and the shell
+loop that respawned the daemon are both gone, and the output of the daemon
+goes to the journal.
index 0c29c0eeceade316ab02df2b70f423eec98782c4..e661b3e14b5edbfd2e2612147c86c0b4c8e57728 100755 (executable)
@@ -8,6 +8,11 @@
 # Short-Description: manage brisk daemon
 ### END INIT INFO
 
+# NOTE: this script is for machines without systemd. Where systemd is in
+# charge, "INSTALL.sh system" writes a unit in Etc instead and does not touch
+# /etc/init.d: debian 13 dropped the sysv compatibility generator, so this
+# script would simply never be run. See WARNING.txt.
+
 BPATH="xx/home/nastasi/web/brisk"
 PPATH="xx/home/nastasi/brisk-priv"
 # screen suffix