Skip to content

Seed the test-time artifacts and re-check failed lookups in CI - #5

Open
gortazar wants to merge 1 commit into
mainfrom
ci-cache-resilience
Open

gortazar wants to merge 1 commit into
mainfrom
ci-cache-resilience

Conversation

@gortazar

Copy link
Copy Markdown
Contributor

Makes the matrix resistant to the Maven cache failure that turned run 40870887229 red on parte_2/tema_2.6_despliegue/despliegue_ejem1:

maven-surefire-plugin:3.5.5:test: The following artifacts could not be resolved:
org.apache.maven.surefire:common-java5:jar:3.5.5 (absent):
Could not find artifact ... in central

First, a correction

My earlier comment on #4 said the shared cache had carried a bad marker into that job. That was wrong, and the run says so: one build job failed while 85 of the 86 projects use the same surefire 3.5.5. A poisoned shared cache would have taken all 85 down, not one. The cache the build jobs restore is also never written back — actions/cache only saves on a key miss, and the warm job is the only miss — so a marker written inside a build job dies with it.

The failure was local to that job, and -U alone would not have prevented it.

What it actually is

dependency:go-offline does not resolve what surefire pulls at test time. So every build job was fetching the JUnit Platform provider from Central on its own — 86 jobs asking for the same nine artifacts simultaneously, which is precisely the burst warm-cache exists to prevent. One of those requests came back as not found.

Change 1: seed the test-time artifacts (addresses the observed failure)

The warm job now runs the tests of one project, leaving the provider in the cache for everyone else. Measured in clean local repositories with Maven 3.10.0, the version on the runners:

Step Result
mvn test on parte_4/tema_4.2/ejemplo-2, empty repo pulls 9 surefire artifacts, common-java5 among them
A Spring Boot project built on that same repo needs 0 additional surefire artifacts

ejemplo-2 is the seed because it is the only project with no Spring and no containers: one test, fractions of a second.

Unlike the warming loop, this step has a precise expectation, so it asserts the provider landed and fails if it did not. Warming that silently stops warming puts the burst back with nobody noticing. The assertion was exercised locally for all three cases: provider present, provider missing, directory absent.

Change 2: -U on the Maven invocations (addresses a failure that has not happened)

This is the hardening, and it is for a different and worse class: if a bad marker ever does reach the shared cache, every job inherits a permanent "not found" for an artifact that is really there.

Reproduced rather than assumed, with a local repository that returns 404 for exactly one artifact and proxies the rest to Central:

  1. Resolve common-java5:3.5.5 while it 404s → Maven 3.10.0 writes .lastUpdated files whose contents are .error= (empty — the not-found flavour, distinct from a transfer error, which writes no marker at all).
  2. Make the artifact available again and resolve without -U → still (absent), still refuses to fetch. The marker is sticky.
  3. Resolve with -U → fetches it, jar lands.

The cost was measured too, since -U forcing re-checks could have made the Central traffic worse: on a complete cache it is 0 extra remote requests and about a second.

Proven versus assumed

Proven: the seed pulls the nine artifacts; a Boot project then needs none; -U clears a recorded absence that otherwise persists; -U costs no extra requests on a warm cache; the new assertion fires correctly in all three states; only one job failed in the original run.

Not proven, and not provable by this PR going green: that the observed failure will not recur. A green run is also what a healthy cache looks like, so the matrix passing here is consistent with both the fix working and the original failure simply not repeating. What can be said is narrower and structural: the build jobs no longer ask Central for the artifact that failed, because it is in the cache before they start.

Deliberately not changed: the warming loop still treats a per-project failure as a warning and exits 0. The premise for tightening it was that go-offline had left a bad marker while returning 0 — and per the correction above, it had not. Tightening a detector on a false premise seemed worse than leaving it.

Run 40870887229 failed one build job on an artifact that exists:

    maven-surefire-plugin:3.5.5:test: The following artifacts could not be
    resolved: org.apache.maven.surefire:common-java5:jar:3.5.5 (absent):
    Could not find artifact ... in central

Correcting the first reading of this, which said the shared cache had
carried a bad marker into the job. It had not. One build job failed while
85 of the 86 projects use the same surefire 3.5.5, so a poisoned shared
cache would have taken all of them down, not one. The cache the build
jobs restore is also never written back: actions/cache only saves on a
key miss, and the warm job is the only miss. The failure was local to
that job.

What it really is: dependency:go-offline does not resolve what surefire
pulls at test time, so every build job was fetching the JUnit Platform
provider from Central on its own. 86 jobs asking for the same nine
artifacts at the same time is the burst this whole job exists to avoid,
and one of them came back as not found.

So the warm job now runs the tests of one project, which leaves the
provider in the cache for everyone else. Measured in a clean local
repository with Maven 3.10.0, the version on the runners:

- parte_4/tema_4.2/ejemplo-2 pulls all nine surefire artifacts,
  common-java5 among them.
- A Spring Boot project built afterwards on that same repository needs
  zero additional surefire artifacts, so seeding once covers the rest.

ejemplo-2 is the seed because it is the only project with no Spring and
no containers: one test, fractions of a second. Unlike the warming loop,
this step has a precise expectation, so it asserts the provider landed
and fails if it did not; warming that silently stops warming puts the
burst back without anyone noticing.

-U is the second, separate change, and it addresses a failure that has
not happened yet: if a bad marker ever does reach the shared cache, every
job inherits a permanent "not found" for an artifact that is really
there. Reproduced with a repository that returns 404 for one artifact:
Maven 3.10.0 writes .lastUpdated files with an empty .error, and a later
resolution reports (absent) and refuses to fetch even once the artifact
is available again. -U clears it. On a complete cache it costs no extra
requests and about a second.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Copilot AI balanced review requested due to automatic review settings October 31, 2026 14:18

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 Changes recommended

An exact-match Maven cache hit prevents the warm job’s seeded artifacts from being saved, so matrix jobs can restore the old cache and still download missing artifacts concurrently.

1 open issue
What changed in this PR

This PR strengthens Maven cache warming for the project matrix by seeding Surefire test-time artifacts and enabling retries of previously failed artifact lookups.

Changes:

  • Runs the lightweight ejemplo-2 tests during cache warming to fetch the JUnit Platform provider.
  • Verifies that the provider exists and lists cached Surefire artifacts in the job summary.
  • Adds -U to Maven warming and build commands to recheck cached artifact absences.
File Description
.github/​workflows/​maven-build.yml Adds test-time artifact seeding, provider validation, and Maven lookup hardening.

Review effort: Balanced

Comment on lines +115 to +117
mvn -B -ntp -U -f parte_4/tema_4.2/ejemplo-2/pom.xml \
-Dmaven.wagon.http.retryHandler.count=5 \
test
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.

2 participants