You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
[Bug]: LogMessageWaitStrategy waits for the full startup timeout after the container exits #12151
If the container dies before the log line shows up LogMessageWaitStrategy still waits the whole startup timeout. We hit this in CI where a container crashes during startup and each attempt burns the full 10 min timeout before failing.
FrameConsumerResultCallback sends OutputFrame.END to the consumer when the log stream closes but WaitingConsumer.waitUntil treats it like any other frame that doesn't match and keeps polling until the deadline. HostPortWaitStrategy already has .failFast("container is no longer running", ...) - log waits don't have anything like that.
Container is gone after ~2 s but start() only fails after the timeout.
Would be nice if the wait failed as soon as it sees END before a match, e.g. with "container stopped before the expected log output". DockerHealthcheckWaitStrategy and HttpWaitStrategy look the same to me (retry until timeout) so maybe they need it too.
We worked around it with a wrapper wait strategy that cancels the wait from a waitContainerCmd callback when the container exits.
Relevant log output
failed after 61.8 s: Timed out waiting for log output matching '.*never.*'
Proposed approach: fail fast as soon as the target is no longer running, reusing the Awaitility failFast mechanism that HostPortWaitStrategy already uses:
.failFast("container is no longer running", () -> !waitStrategyTarget.isRunning())
The existing WaitingConsumer.waitUntil(...) call would run unchanged on AbstractWaitStrategy.EXECUTOR (same startup timeout, same times semantics), while the calling thread polls isRunning() alongside it. If the container exits before a match, the wait is aborted with Container stopped before the expected log output matching '<regEx>' was produced instead of burning the full startup timeout. A short grace period lets output buffered right before the exit still match, so a container that prints the expected message and then exits keeps succeeding.
We considered detecting OutputFrame.END in the wait predicate instead, but frames are polled from the buffer newest-first (pollLast in WaitingConsumer), so END can be examined before earlier buffered frames — aborting on it could false-fail a container whose expected output is still in the buffer. Checking isRunning() avoids that.
For the repro from the issue (alpine printing started, then exit 1 after ~2s, waiting for .*never.* with a 60s timeout), start() fails in a few seconds instead of after the full timeout. Timeout semantics for a still-running container are unchanged.
Activity
sygkanrt30 commentedon Nov 4, 2026
Hi @kiview! I'd like to take this issue if nobody is working on it.
Can you assign it to me? Thanks!
Inf1mum commentedon Nov 4, 2026
Hi! I'd like to pick this up.
Proposed approach: fail fast as soon as the target is no longer running, reusing the Awaitility
failFastmechanism thatHostPortWaitStrategyalready uses:The existing
WaitingConsumer.waitUntil(...)call would run unchanged onAbstractWaitStrategy.EXECUTOR(same startup timeout, sametimessemantics), while the calling thread pollsisRunning()alongside it. If the container exits before a match, the wait is aborted withContainer stopped before the expected log output matching '<regEx>' was producedinstead of burning the full startup timeout. A short grace period lets output buffered right before the exit still match, so a container that prints the expected message and then exits keeps succeeding.We considered detecting
OutputFrame.ENDin the wait predicate instead, but frames are polled from the buffer newest-first (pollLastinWaitingConsumer), soENDcan be examined before earlier buffered frames — aborting on it could false-fail a container whose expected output is still in the buffer. CheckingisRunning()avoids that.For the repro from the issue (alpine printing
started, thenexit 1after ~2s, waiting for.*never.*with a 60s timeout),start()fails in a few seconds instead of after the full timeout. Timeout semantics for a still-running container are unchanged.PR to follow.