@@ -668,7 +668,7 @@ jobs:
668668 run : cmake --preset gcc-release -DFASTCACHED_BUILD_TESTS=OFF -DFASTCACHED_PACKAGE_ROOT_PREFIX=ON -DFASTCACHED_REQUIRE_EXACT_VERSION=${{ env.FASTCACHED_REQUIRE_EXACT_VERSION }}
669669
670670 - name : " Build"
671- run : cmake --build --preset gcc-release --target fastcached fastcache-cc
671+ run : cmake --build --preset gcc-release --target fastcached fastcache-cc fastcache-compile-node
672672
673673 - name : " Package"
674674 working-directory : out/build/gcc-release
@@ -710,11 +710,15 @@ jobs:
710710
711711 # The binaries, the units and the config must each land in the one
712712 # location that works; /usr/etc or /lib would silently never be read.
713- for path in ./usr/bin/fastcached ./usr/bin/fastcache-cc \
713+ for path in ./usr/bin/fastcached ./usr/bin/fastcache-cc ./usr/bin/fastcache-compile-node \
714714 ./usr/lib/systemd/system/fastcached.service \
715715 ./usr/lib/systemd/user/fastcached.service \
716716 ./usr/lib/sysusers.d/fastcached.conf \
717717 ./usr/lib/tmpfiles.d/fastcached.conf \
718+ ./usr/lib/systemd/system/fastcache-compile-node.service \
719+ ./usr/lib/systemd/system/fastcache-compile-node.socket \
720+ ./usr/lib/sysusers.d/fastcache-node.conf \
721+ ./etc/fastcached/compile-node.env \
718722 ./etc/fastcached/fastcached.yaml; do
719723 grep -qx "$path" /tmp/deb-paths.txt || { echo "::error::missing $path"; exit 1; }
720724 done
@@ -739,17 +743,26 @@ jobs:
739743 rpm -qlp "$rpmfile" > /tmp/rpm-paths.txt
740744 rpm -qcp "$rpmfile" > /tmp/rpm-config.txt
741745
742- for path in /usr/bin/fastcached /usr/bin/fastcache-cc \
746+ for path in /usr/bin/fastcached /usr/bin/fastcache-cc /usr/bin/fastcache-compile-node \
743747 /usr/lib/systemd/system/fastcached.service \
744748 /usr/lib/systemd/user/fastcached.service \
745749 /usr/lib/sysusers.d/fastcached.conf \
746750 /usr/lib/tmpfiles.d/fastcached.conf \
751+ /usr/lib/systemd/system/fastcache-compile-node.service \
752+ /usr/lib/systemd/system/fastcache-compile-node.socket \
753+ /usr/lib/sysusers.d/fastcache-node.conf \
754+ /etc/fastcached/compile-node.env \
747755 /etc/fastcached/fastcached.yaml; do
748756 grep -qx "$path" /tmp/rpm-paths.txt || { echo "::error::missing $path"; exit 1; }
749757 done
750758
751- grep -qx '/etc/fastcached/fastcached.yaml' /tmp/rpm-config.txt \
752- || { echo "::error::config not marked %config"; exit 1; }
759+ # Both, and for the same reason: an upgrade that reset either one is a
760+ # silent regression. compile-node.env is what makes the worker work at
761+ # all, so resetting it un-registers the worker with no error anywhere.
762+ for path in /etc/fastcached/fastcached.yaml /etc/fastcached/compile-node.env; do
763+ grep -qx "$path" /tmp/rpm-config.txt \
764+ || { echo "::error::$path not marked %config"; exit 1; }
765+ done
753766
754767 # Install for real and drive traffic through it. The GitHub runner has a
755768 # live systemd, so this exercises the actual unit — the service account,
@@ -803,6 +816,75 @@ jobs:
803816 sudo systemctl stop fastcached
804817 test "$(systemctl show -p Result --value fastcached)" = success
805818
819+ - name : " Socket-activate the compile worker on real systemd"
820+ run : |
821+ set -euo pipefail
822+
823+ # The account the sysusers.d entry must have created. Without it the
824+ # unit fails to start with "user does not exist", which says nothing
825+ # about which package forgot to create it.
826+ id fastcache-node >/dev/null \
827+ || { echo "::error::the fastcache-node service account was not created"; exit 1; }
828+
829+ # A scheduler that is not there. The worker must still start, warn and
830+ # keep retrying -- a fleet where the scheduler restarts must not turn
831+ # into a fleet of dead workers.
832+ printf 'FASTCACHE_NODE_ARGS=--scheduler=127.0.0.1:6675 --advertise=127.0.0.1:6676 --toolchain=/usr/bin/g++\n' \
833+ | sudo tee /etc/fastcached/compile-node.env >/dev/null
834+
835+ # Enabling the SOCKET is what enables the worker; the service carries
836+ # no [Install] on purpose.
837+ sudo systemctl enable --now fastcache-compile-node.socket
838+ systemctl is-active --quiet fastcache-compile-node.socket \
839+ || { echo "::error::the socket unit did not start"; exit 1; }
840+
841+ # Nothing should be running yet -- that is the whole point of
842+ # activation. An already-active service here means the socket was
843+ # bypassed and the unit is just an ordinary daemon.
844+ systemctl is-active --quiet fastcache-compile-node \
845+ && { echo "::error::the service started without a connection"; exit 1; }
846+
847+ # One connection activates it.
848+ timeout 10 bash -c 'exec 3<>/dev/tcp/127.0.0.1/6676' || true
849+
850+ # Waited for by its OUTPUT, not by is-active. Type=simple is reported
851+ # active the moment systemd forks, while this worker still has to walk
852+ # its toolchain's include tree to compute a fingerprint -- seconds of
853+ # real work. Polling is-active therefore answers "has it started",
854+ # which is not the question; the first version of this step asked it
855+ # and read an empty journal.
856+ for _ in $(seq 1 90); do
857+ sudo journalctl -u fastcache-compile-node --no-pager > /tmp/node-log.txt 2>/dev/null || true
858+ grep -q 'compile node ready' /tmp/node-log.txt && break
859+ sleep 1
860+ done
861+ cat /tmp/node-log.txt
862+ grep -q 'compile node ready' /tmp/node-log.txt || {
863+ echo "::error::a connection did not bring the worker up"
864+ systemctl status fastcache-compile-node --no-pager || true; exit 1; }
865+
866+ # It must have ADOPTED the socket rather than bound its own. Binding
867+ # would have failed against the socket unit already holding the port,
868+ # so a running service that did not adopt is a service listening
869+ # somewhere nobody was told about.
870+ grep -q 'adopted a socket-activated listener' /tmp/node-log.txt \
871+ || { echo "::error::the worker did not adopt the activated socket"; exit 1; }
872+
873+ test "$(systemctl show -p User --value fastcache-compile-node)" = fastcache-node
874+
875+ # The stop path, on real systemd and on an ADOPTED descriptor. This is
876+ # the assertion that matters most here: POSIX does not unblock a parked
877+ # accept() when the listener is closed, so a worker without a receive
878+ # timeout hangs until systemd escalates to SIGKILL -- and that bug has
879+ # already shipped once, on the ordinary bind path. `Result=success`
880+ # distinguishes a clean exit from a killed one; `is-system-running`
881+ # would not.
882+ sudo systemctl stop fastcache-compile-node
883+ test "$(systemctl show -p Result --value fastcache-compile-node)" = success \
884+ || { echo "::error::the worker did not stop cleanly"
885+ sudo journalctl -u fastcache-compile-node --no-pager; exit 1; }
886+ sudo systemctl stop fastcache-compile-node.socket
887+
806888 - name : " Verify an upgrade keeps local config edits"
807889 working-directory : out/build/gcc-release
808890 run : |
@@ -818,8 +900,13 @@ jobs:
818900 set -euo pipefail
819901 sudo apt-get purge -y fastcached
820902 test ! -e /usr/lib/systemd/system/fastcached.service
903+ test ! -e /usr/lib/systemd/system/fastcache-compile-node.service
904+ test ! -e /usr/lib/systemd/system/fastcache-compile-node.socket
821905 # A leftover wants-symlink makes systemd log a failure on every boot.
822906 test ! -e /etc/systemd/system/multi-user.target.wants/fastcached.service
907+ # The socket is the unit that gets enabled, so it is the one that
908+ # leaves a symlink behind if the postrm forgets it.
909+ test ! -e /etc/systemd/system/sockets.target.wants/fastcache-compile-node.socket
823910
824911 - name : " Upload packages"
825912 uses : actions/upload-artifact@v4
@@ -1001,15 +1088,15 @@ jobs:
10011088 -DFASTCACHED_REQUIRE_EXACT_VERSION=${{ env.FASTCACHED_REQUIRE_EXACT_VERSION }}
10021089
10031090 - name : " Build"
1004- run : cmake --build out/build/macos-package --target fastcached fastcache-cc
1091+ run : cmake --build out/build/macos-package --target fastcached fastcache-cc fastcache-compile-node
10051092
10061093 - name : " Verify the binaries are redistributable"
10071094 # The regression that would otherwise ship silently: everything builds,
10081095 # every test passes, and the package refuses to launch on any machine
10091096 # without the build host's Homebrew prefix.
10101097 run : |
10111098 set -euo pipefail
1012- for tool in fastcached fastcache-cc; do
1099+ for tool in fastcached fastcache-cc fastcache-compile-node ; do
10131100 binary="out/build/macos-package/target/$tool"
10141101 echo "== $tool"; otool -L "$binary"
10151102 strays="$(otool -L "$binary" | tail -n +2 | awk '{print $1}' | grep -v '^/usr/lib/' || true)"
@@ -1157,7 +1244,7 @@ jobs:
11571244 run : cmake --preset cl-release -DFASTCACHED_BUILD_TESTS=OFF -DFASTCACHED_REQUIRE_EXACT_VERSION=${{ env.FASTCACHED_REQUIRE_EXACT_VERSION }}
11581245
11591246 - name : " Build"
1160- run : cmake --build --preset cl-release --target fastcached fastcache-cc
1247+ run : cmake --build --preset cl-release --target fastcached fastcache-cc fastcache-compile-node
11611248
11621249 # On failure CPack only says "check wix.log", which lives in the build
11631250 # tree and is otherwise discarded with the runner — so the actual WiX
0 commit comments