Skip to content

Bump GitHub Actions to Node 24-compatible major versions - #660

Closed
pancetta wants to merge 10 commits into
masterfrom
fix/ci-coverage-python-pins
Closed

Bump GitHub Actions to Node 24-compatible major versions#660
pancetta wants to merge 10 commits into
masterfrom
fix/ci-coverage-python-pins

Conversation

@pancetta

Copy link
Copy Markdown
Member

Summary

Every CI run prints "Node.js 20 is deprecated" warnings for actions still declaring runs.using: node20 in their action.yml, which GitHub now force-runs on Node 24 anyway. Same issue previously seen and fixed in the RSE_course_JuRSE project.

Verified each action's actual runs.using value at both the currently-pinned and candidate new major version before bumping (not just assumed from version numbers):

  • actions/checkout: v1 (lint job only — a legacy pre-Node "plugin" action, not itself the source of the node20 warning, but badly outdated) and v4 (node20) → v7 (node24)
  • actions/upload-artifact: v4 (node20) → v7 (node24)
  • actions/download-artifact: v4 (node20) → v8 (node24)
  • mamba-org/setup-micromamba: v1 (node20) → v3 (node24) — confirmed the two inputs actually used here (environment-file, create-args) are unchanged in v3

Left alone (confirmed not implicated in the warning at all):

  • codecov/codecov-action@v5 — composite action, no Node runtime
  • py-cov-action/python-coverage-comment-action@v3 — Docker action, no Node runtime
  • JamesIves/github-pages-deploy-action@v4 — already node24

Test plan

  • CI run shows no "Node.js 20 is deprecated" warnings
  • No breaking changes from the version jumps (checkout, artifact upload/download, micromamba all behave as before)

🤖 Generated with Claude Code

pancetta and others added 10 commits August 17, 2026 10:48
…ocess-heavy project envs

Weekly scheduled CI has failed 5+ weeks running: mpi4py/petsc/pytorch jobs
and several project test jobs die within ~1s of pytest collection starting,
SIGTERM'd (exit 143/15) with no traceback.

Two independent causes, confirmed by bisecting CI run logs:

- `coverage` is unpinned across the test envs, so CI silently rides the
  newest conda-forge release every run. The last known-good scheduled run
  resolved coverage 7.15.0; the very next run (two days later) resolved
  7.15.1 and immediately hit exit-143 failures, and every run since has
  failed the same way through 7.15.4 (latest as of writing). The failures
  are limited to jobs that spawn subprocesses (MPI ranks, multiprocessing),
  consistent with coverage's `concurrency=['multiprocessing']` subprocess-
  tracking hook (installed via sitecustomize.py) interacting badly with
  process/thread init in mpi4py/petsc4py/torch. Pinned to 7.15.0, the last
  version with an extended clean track record in this CI.

- Several project environment.yml files (and Monodomain's) don't pin a
  Python version at all, so micromamba occasionally resolves a brand new
  Python (3.14) before the full compiled-dependency chain (mpi4py, mpich,
  petsc4py, fenics, numba) is ready for it on conda-forge, causing the same
  SIGTERM-during-collection symptom. Capped to the range pySDC already
  tests explicitly (3.10-3.13), scoped only to the projects that actually
  depend on those compiled/subprocess-heavy packages.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…tracking

The coverage==7.15.0 pin from the previous commit doesn't actually fix the
exit-143 CI failures: this branch's own CI run hit the identical SIGTERM
signature on mpi4py/petsc/pytorch/project jobs even under 7.15.0, at a rate
(~15% of jobs) comparable to unpinned 7.15.4. The one prior "clean" run
under 7.15.0 was a sample size of one, not evidence the version is safe.
It also broke environment solving for StroemungsRaum, whose environment.yml
(pulling in fenics) couldn't satisfy the pin's exact version constraint
against packages `--freeze-installed` had already locked in.

Since the race isn't tied to a specific coverage release, remove the thing
that's actually crashing: coverage's `concurrency = ['multiprocessing']`
subprocess-tracking hook (installed via sitecustomize.py +
coverage.process_startup() in CI), which intermittently SIGTERMs
subprocess-spawning test jobs during collection. Coverage is left unpinned
again. Trade-off: coverage running inside MPI-rank/multiprocessing
subprocesses is no longer measured.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…sion pins

Removing concurrency=['multiprocessing'] and the sitecustomize.py subprocess
hook did NOT fix the exit-143 failures: this branch's own follow-up CI run
hit the identical instant-SIGTERM signature (mpi4py/petsc/pytorch/project
jobs, ~1s into collection, no traceback) with subprocess coverage tracking
fully disabled. That falsifies the coverage-causation theory this and the
prior commit were built on - removing the suspected mechanism achieved
nothing, so there's no reason to pay its real cost (losing coverage
measurement inside MPI-rank/multiprocessing subprocesses). Restored.

The Python-version pins are unaffected by this - they fix a separate,
confirmed, unrelated bug (unpinned project envs occasionally resolving
Python 3.14 before the compiled-dependency chain is ready for it) and
stay in place.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Two independent things going on, both aimed at reducing how hard this
workflow hammers GitHub's own runner-provisioning backend, which has had
documented capacity/concurrency problems this year (RCA'd incidents on
2026-07-09 and 2026-08-06, the latter an explicit "existing capacity and
concurrency weakness" in GitHub's own Actions job-generation service) -
this workflow's ~80-job matrix, launched twice per PR push, is exactly the
kind of burst load that stresses that.

- Add a workflow-level `concurrency` group keyed on branch name (using
  `head_ref || ref_name`, which resolves to the same string for a push
  event and a pull_request event on the same branch - `ref` would not,
  since it carries a `refs/heads/` prefix on push events). A push to a
  branch with an open PR fires both `push` and `pull_request` for the same
  commit; this cancels the stale duplicate instead of running both to
  completion. Preserves existing trigger behavior (push still runs CI on
  every branch) rather than narrowing when CI runs.

- Cap `max-parallel: 8` on the two large matrix jobs (user_cpu_tests_linux:
  20 combinations, project_cpu_tests_linux: 17), so GitHub isn't asked to
  provision ~37 runners for those two jobs alone in the same instant.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Direct evidence from this PR's own CI runs: re-running previously-failed
jobs on identical code produces a *different* failure set each time
(pytorch 3.10/3.12 passed on rerun while AllenCahn_Bayreuth and mpi4py 3.10
failed again) - the signature of non-deterministic external flakiness, not
a reproducible bug. Combined with the documented GitHub Actions incidents
this year (see prior commits), manual re-running already works as a
workaround; this automates it.

Retry is scoped tightly to avoid masking real problems: only exit 143 or
15 (the exact signature observed - instant SIGTERM within ~1s of pytest
starting, no traceback) triggers a second attempt. Any other non-zero exit
(e.g. exit 1 from genuine test failures) fails immediately on the first
attempt, no retry, so this can't hide a real regression behind a "flaky
test" label.

Applied to the three "Run pytest for CPU stuff" steps that have shown this
signature (user_cpu_tests_linux, project_cpu_tests_linux, monodomain).
Left user_libpressio_tests/user_firedrake_tests alone - no evidence they
need it.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
…egression theory

Version-bisected the runner image across every observed pass/fail this
session: last clean run (2026-07-15) used image 20260705.232.1
(kernel 6.17.0-1018-azure); first sustained-failure run (2026-07-20) used
20260714.240.1 (kernel bumped to 6.17.0-1020-azure), and every image
since (through 20260810.271.1 today) has kept failing. Combined with the
region clustering already found (failures concentrated in
centralus/northcentralus/westcentralus/westus3, zero in eastus/eastus2/
westus/westus2), this points at a kernel-level regression in GitHub's
ubuntu-latest (24.04) image, likely rolled out unevenly by region, that
MPICH's process/shared-memory init doesn't handle cleanly.

Testing that theory directly: switch the three jobs that have shown this
signature (user_cpu_tests_linux, project_cpu_tests_linux,
user_monodomain_tests_linux) to ubuntu-22.04, a separately-versioned image
lineage that may not carry the same kernel change. Left lint,
user_libpressio_tests, user_firedrake_tests (containerized, never showed
this failure) and coverage_comment_on_pr (no MPI) on ubuntu-latest.

This is explicitly an experiment - revert to ubuntu-latest if it doesn't
measurably reduce the failure rate.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The ubuntu-22.04 experiment (previous commit) is inconclusive-to-negative:
the exit-143 signature still occurred on that separately-versioned image
lineage (DAE, fenics 3.13, Resilience, pytorch 3.13 failed), which rules
out the GitHub runner-image kernel-bump theory from two commits ago.
Reverted to ubuntu-latest for all jobs.

What survived that test: the region correlation. The four new failures
landed in westus3 (x3) and centralus (x1) - the same regions flagged
before - while all ~30 other jobs in the same run, spread across
eastus/eastus2/westus/westus2/northcentralus/westcentralus/mexicocentral,
passed. Switching OS image didn't change which regions fail, which points
below the OS/kernel layer entirely, into the underlying Azure host/
network infrastructure in those specific datacenters - something no
runner image or package version choice can work around.

Since GitHub-hosted runners don't expose region selection, and the
existing per-step retry loops rerun the command on the *same* runner (so
can't help when the runner/region itself is the problem), add a
`rerun-failed-jobs` job that calls the GitHub API to rerun failed jobs in
a fresh attempt (new runner, new shot at a healthy region) via
`gh run rerun --failed`. Capped at 3 total attempts via
`github.run_attempt` to avoid looping forever. Coarser than the per-step
retry - it reruns on any job failure, not just exit 143/15, since the
rerun API doesn't expose that distinction - but a genuinely failing test
still ends up red after attempts are exhausted, just slower.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
The rerun-failed-jobs job from the last commit failed immediately every
time: "run 32034660678 cannot be rerun; This workflow is already running".
GitHub refuses to rerun a run that still has an active job - and a job
calling `gh run rerun` on its own run can never observe that run as
anything but in-progress, since it's itself one of the jobs keeping it
that way. Structurally can't work from inside the same run.

Moved the logic to a new auto_rerun_failed_jobs.yml, triggered by
workflow_run (types: [completed]) on "CI pipeline for pySDC" - which only
fires once that run has genuinely finished, so the rerun call succeeds.
This is the same pattern postprocess.yml already uses successfully in
this repo for the exact same trigger. Removed the broken in-workflow job
from ci_pipeline.yml.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Per-step retry (loop the pytest command on SIGTERM) is redundant now that
auto_rerun_failed_jobs.yml exists, and we already have direct evidence it
doesn't help: two in-place retry attempts in the same job failed
identically (same runner, same likely-bad region both times). The
job-level rerun is the one with actual evidence of working, since it gets
a fresh runner. Removed the loops from all three "Run pytest for CPU
stuff" steps, back to a plain single invocation.

Also investigated the coverage_comment_on_pr failure from the last clean
run: a genuine, transient GitHub API 504 Gateway Timeout on
GET /repos/.../pulls/659, unrelated to permissions (the action's own
"permissions set incorrectly" message is generic boilerplate it prints
for any API failure) and unrelated to the MPI/SIGTERM investigation.
Marked that step continue-on-error: true, since a missing coverage
comment is cosmetic and shouldn't fail the PR's CI status.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Every CI run has been printing "Node.js 20 is deprecated" warnings for
actions still declaring runs.using: node20 in their action.yml, forced
onto Node 24 by the runner. Verified each action's actual runs.using
value at both the currently-pinned and latest major version before
bumping, rather than assuming:

- actions/checkout: v1 (lint job only, a legacy pre-Node "plugin" action,
  not itself node20 but badly outdated) and v4 (node20) -> v7 (node24)
- actions/upload-artifact: v4 (node20) -> v7 (node24)
- actions/download-artifact: v4 (node20) -> v8 (node24)
- mamba-org/setup-micromamba: v1 (node20) -> v3 (node24); confirmed the
  two inputs actually used here (environment-file, create-args) are
  unchanged in v3

Left codecov/codecov-action@v5, py-cov-action/python-coverage-comment-
action@v3, and JamesIves/github-pages-deploy-action@v4 alone: confirmed
these are composite/docker/already-node24 respectively, not implicated
in the warning at all.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
@github-actions

github-actions Bot commented Aug 18, 2026

Copy link
Copy Markdown

Coverage report

This PR does not seem to contain any modification to coverable code.

@pancetta

Copy link
Copy Markdown
Member Author

Superseded by #661 — this branch accidentally carried the full commit history of the already-merged #659 even though the file diff was clean. Same change, clean branch, over there.

@pancetta pancetta closed this Aug 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant