diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index e7cb803..5d8c3df 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -114,18 +114,58 @@ jobs: chmod -R a+rX /var/www/html/project2 curl -fsS -o /dev/null -w 'GET /project2/ : %{http_code}\n' http://localhost/project2/ - # crate-api only exists from M2 onward. Fail the deploy loudly if the - # unit is present but down; skip quietly if it has not been created yet. - - name: Restart the GraphQL API if present + # Restarting the GraphQL API is M2 work. Until `server/` exists in this + # repository there is nothing to deploy, and restarting the unit would + # just bring back whatever was last installed on the VM by hand. + # + # Two things here are deliberately not what the first version did: + # + # - The unit check is `[ -f ... ]`, not `systemctl list-unit-files | grep`. + # `grep -q` exits on the first match and closes the pipe, `systemctl` + # gets SIGPIPE and dies, and with `pipefail` the whole pipeline reports + # failure. So the `if` took the else branch and skipped a service that + # was definitely there. The log showed "Failed to print table: Broken + # pipe". Reported by rachelks. + # + # - The restart needs `sudo`, and the runner has no TTY. That needs a + # NOPASSWD rule scoped to exactly these commands. Without it the step + # dies with "sudo: A terminal is required to authenticate". + - name: Restart the GraphQL API if the server is deployed run: | set -euo pipefail - if systemctl list-unit-files | grep -q '^crate-api.service'; then - sudo systemctl restart crate-api - sleep 2 - curl -fsS -o /dev/null -w 'POST /graphql : %{http_code}\n' \ + if [ ! -f /etc/systemd/system/crate-api.service ]; then + echo "crate-api.service is not installed. Skipping API restart." + exit 0 + fi + if [ ! -d server ]; then + echo "No server/ in this repository yet (arrives in M2). Skipping API restart." + exit 0 + fi + if [ ! -f server/dist/index.js ]; then + echo "::error::server/ exists but server/dist/index.js does not. Was 'pnpm build' run?" + exit 1 + fi + sudo /usr/bin/systemctl restart crate-api + + # `Type=simple` makes systemd report active as soon as the process is + # spawned, well before Node has bound the port. Measured on the VM, + # the API answers again after about 1850 ms, so a fixed `sleep 2` + # leaves a margin of roughly 120 ms. That was enough to return 503 + # through the Apache proxy on at least one run. Poll instead. + printf 'Waiting for the API' + for _ in $(seq 1 30); do + code=$(curl -s -o /dev/null -w '%{http_code}' --max-time 2 \ -X POST http://localhost/graphql \ -H 'content-type: application/json' \ - -d '{"query":"{ __typename }"}' - else - echo "crate-api.service not installed yet (arrives in M2). Skipping." - fi + -d '{"query":"{ __typename }"}' 2>/dev/null || echo 000) + if [ "$code" = "200" ]; then + echo + echo "POST /graphql : 200" + exit 0 + fi + printf '.' + sleep 1 + done + echo + echo "::error::crate-api restarted but /graphql never returned 200 (last code ${code})." + exit 1