Repository navigation
Apply the startup timeout as one deadline from container start - #1584
Draft
cristianrgreco wants to merge 7 commits into
Draft
cristianrgreco wants to merge 7 commits into
cristianrgreco wants to merge 7 commits into
Conversation
This was referenced Oct 12, 2026
cristianrgreco
marked this pull request as draft
October 13, 2026 09:15
containerStarted hook
cristianrgreco
changed the base branch from
main
to
claude/deadline-aware-poll-helper-e07af6
October 13, 2026 16:27
This was referenced Oct 13, 2026
This branch has not been deployed
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
withStartupTimeout(ms)reads as "the container must be ready within this long", but it was applied per wait. The wait strategy got the full timeout, counted from when it began, and modules that wait again incontainerStarted(Kafka, Redpanda, Couchbase) started another one. A Kafka container with its 180 second default could run for close to 360 seconds before failing.A startup timeout set on the container is now one deadline, counted from when the container is started. It is an
AbortSignalcreated once at the top and passed down, the way a context is passed in Go. Nothing computes how much time is left. Part of #1582.Stacked on #1594, which makes every wait a signal-aware
poll. The base of this PR is that branch.GenericContainercreates the signal just before it starts the container.restart()creates one once Docker has restarted the container.DockerComposeEnvironment.up()creates one for all of its containers oncedocker compose upreturns.waitForContainerandWaitStrategy.waitUntilReadytake the signal as an optional last argument, andpolltakes it assignal. A wait that is still running when the signal aborts rejects with its own timeout error, so the error messages stay the same.containerStartingandcontainerStartedreceive the signal as an optional last argument.containerStarted. Couchbase passes it to each of its waits and no longer works out the time left for each one.This follows testcontainers-go, where the caller's context is the ceiling and each wait strategy derives its timeout from it:
wait/host_port.go,lifecycle.go.Behaviour changes
Only containers and Compose environments with a startup timeout set on them are affected. That includes the modules that set a default in their constructor.
containerStarting.Wait.forAllwith its own, longer timeout no longer outlasts the container's or the Compose environment's startup timeout.containerStartedhas the startup timeout (60 seconds when none is set) as its own timeout, and its error reports that value.Unchanged:
withStartupTimeout(0)fail in the port-binding wait instead of in the wait strategy, which core tests rely on.Left for later, from #1582:
containerStartedand callssuperwithout it.Verification
npm run format,npm run lint,npm run knipandnpm run check-compilesare clean.pollinretry.test.ts, five ingeneric-container-startup-timeout.test.tsand one indocker-compose-environment.test.ts.pollignoring the given signal and the startup signal never aborting, seven of them fail.poll: two time out after 5000ms and one fails withpromise resolved "'result'" instead of rejecting.expected [ false ] to deeply equal [ true ]for the signal being started before the wait strategy, andexpected 63702 to be less than 60000for the wait incontainerStarted.expected 60216 to be less than 60000andexpected 65091 to be less than 60000.common,docker-compose-environment,generic-container-restart.test.tsand the new test file run together: 72 tests pass.wait-strategies: 77 tests pass.generic-containerdirectory run together: 106 of 109 pass, 1 skipped.should restartandshould restart persisting statefail withfetch failedagainst the mapped port after the restart. They pass in the 72-test run above, andshould restartfails the same way onmainwhen that directory is run together.npm-publish.ymldispatched on this branch withv12.2.2): passed.Not breaking
WaitStrategy.waitUntilReady,waitForContainerand the two protected callbacks, and asignaloption onpoll. Custom wait strategies and callback overrides that ignore it compile and behave as before.