Summary
PreparedModeAuthenticationFunctionalTest intermittently hangs on its V2/V2 parameterisations,
consuming the full 30-minute job budget and producing no failing assertion, no stack trace, and
several orphaned JVMs. Seen on test (17.0.19-tem) in CI; not reproduced locally in one attempt on
17.0.14.
Evidence
Same PR, three runs of the same tier:
develop passes the same tier in 4m16s, so ~4–5 minutes is the normal duration and 30 minutes is a
stall rather than slowness.
It is not a fixed case. The first run stalled on client v2, server v2, auto=false, supplied token=true; the re-run passed that one and stalled on a later V2/V2 parameterisation, on a
different executor thread.
Last output before the silence, both times:
PreparedModeAuthenticationFunctionalTest > ... > client v2, server v2, ...
[pool-6-thread-1] INFO io.btrace.client.Client - Successfully started BTrace probe: OnTimerArgTest.java
← ~25 minutes of nothing
##[error]The operation was canceled.
Job cleanup then reports:
Terminate orphan process: pid (3339) (java) ... seven of these
So authentication, negotiation and probe submission all completed. The stall is after that.
Why this is worse than a normal flake
The failure is silent. There is no assertion failure and no thread dump, so localising it required
reading the raw job log and comparing timestamps. Every occurrence costs the whole job budget.
It also reaches the release path: release-smoke runs after the operator has published to Maven
Central and finalize-tag depends on it, so a stall there leaves artifacts on Central with no tag,
no GitHub release and no SDKMAN update — the same shape as a failure, but with no diagnostic.
Unverified hypothesis
Offered as a starting point, not a conclusion — it has not been reproduced.
Every wait inside assertProbeRoundTrip is bounded (started.get(20s), submission.get(10s)), so
a 25-minute silence cannot be the test awaiting an assertion. The probe submission runs on
Executors.newSingleThreadExecutor(), whose threads are non-daemon, and executor.shutdownNow()
interrupts — but a thread blocked in socket I/O does not respond to interrupt. A surviving
non-daemon thread would keep the test JVM alive, so the Gradle worker never exits and the build
stalls with nothing to report. The orphaned JVMs at cleanup are consistent with this.
Suggested changes
Independent of root cause:
- Per-test timeout in the integration harness, so a stall becomes a fast, attributable failure
with a stack dump naming the blocked thread instead of a silent 30-minute job.
- Daemon threads for the test executors, so a thread stuck in socket I/O cannot hold the test
JVM open.
- Consider a thread dump on timeout, which would have made this a one-line diagnosis.
Summary
PreparedModeAuthenticationFunctionalTestintermittently hangs on its V2/V2 parameterisations,consuming the full 30-minute job budget and producing no failing assertion, no stack trace, and
several orphaned JVMs. Seen on
test (17.0.19-tem)in CI; not reproduced locally in one attempt on17.0.14.
Evidence
Same PR, three runs of the same tier:
developpasses the same tier in 4m16s, so ~4–5 minutes is the normal duration and 30 minutes is astall rather than slowness.
It is not a fixed case. The first run stalled on
client v2, server v2, auto=false, supplied token=true; the re-run passed that one and stalled on a later V2/V2 parameterisation, on adifferent executor thread.
Last output before the silence, both times:
Job cleanup then reports:
So authentication, negotiation and probe submission all completed. The stall is after that.
Why this is worse than a normal flake
The failure is silent. There is no assertion failure and no thread dump, so localising it required
reading the raw job log and comparing timestamps. Every occurrence costs the whole job budget.
It also reaches the release path:
release-smokeruns after the operator has published to MavenCentral and
finalize-tagdepends on it, so a stall there leaves artifacts on Central with no tag,no GitHub release and no SDKMAN update — the same shape as a failure, but with no diagnostic.
Unverified hypothesis
Offered as a starting point, not a conclusion — it has not been reproduced.
Every wait inside
assertProbeRoundTripis bounded (started.get(20s),submission.get(10s)), soa 25-minute silence cannot be the test awaiting an assertion. The probe submission runs on
Executors.newSingleThreadExecutor(), whose threads are non-daemon, andexecutor.shutdownNow()interrupts — but a thread blocked in socket I/O does not respond to interrupt. A surviving
non-daemon thread would keep the test JVM alive, so the Gradle worker never exits and the build
stalls with nothing to report. The orphaned JVMs at cleanup are consistent with this.
Suggested changes
Independent of root cause:
with a stack dump naming the blocked thread instead of a silent 30-minute job.
JVM open.