Repository navigation
fix(up): check a depends_on condition before the first poll tick - #14385
Conversation
23db0f0 to
60cc2d6
Compare
|
LGTM, thanks for the fix and for locking the first-check timing in a test. I went through the side effects I could think of and found none: the Could you rebase on I tried that resolution locally on top of |
60cc2d6 to
48a805a
Compare
|
@ndeloof Thanks for the review! Rebased on |
Head branch was pushed to by a user without write access
48a805a to
8f35601
Compare
|
Follow-up: CI caught something my local run missed. I gave |
Signed-off-by: hiroto.toyoda <hiroto.toyoda@dena.com>
44c5500 to
87917c0
Compare
Codecov Report✅ All modified and coverable lines are covered by tests. 📢 Thoughts on this report? Let us know! |
ndeloof
left a comment
There was a problem hiding this comment.
Thanks @htoyoda18, the change itself is good and everything else checks out. One blocking point though: this PR makes an existing test flaky.
TestExecutePlanCanceledCallerReportsNothingMore (pkg/compose/executor_start_test.go) now fails intermittently under -race with api: [Starting] instead of no event:
- on
main: 0 failures out of 150 runs (-race,GOMAXPROCS=2) - on this branch: 20 failures out of 300 (same conditions), about 1 in 300 without the CPU constraint
Repro: GOMAXPROCS=2 go test ./pkg/compose/ -race -count=300 -run 'TestExecutePlanCanceledCallerReportsNothingMore$'
Why: the test cancels the caller's context from inside the first ContainerInspect of the wait. Before this PR that inspection only happened after the first 500ms tick, so the api start node was long parked in its dependency select and ctx.Done() woke it up first. Now the inspection happens on entry, so the cancel can land before that goroutine reaches its select. When it does, done and ctx.Done() are both ready, select picks at random, and api emits a Starting event after the cancellation. The test was relying on that timing without saying so.
The race in runNode itself is not introduced by this PR (it is the same pattern waitDependencyReached fixed by letting ctx win), and I will handle it separately. For this PR the test just needs to stop depending on scheduling. One way: run it under synctest.Test as you already do in TestWaitDependencyFirstCheck, make the mocked inspection wait on a channel, call synctest.Wait() from the test goroutine (it returns once the api node is durably blocked on its dependency), then cancel() and release the inspection.
Please also run the test with -race -count=300 and GOMAXPROCS=2 once fixed.
…rst inspection Signed-off-by: hiroto.toyoda <hiroto.toyoda@dena.com>
Head branch was pushed to by a user without write access
|
@ndeloof Thanks! I fixed the test under |
What this PR does
When a service waits on a dependency with
condition: service_healthyorservice_completed_successfully, Compose always waited for one 500ms poll interval before it checked the dependency for the first time, even when the dependency already satisfied the condition. This PR checks these two conditions as soon as the wait starts, so a no-opdocker compose up -dgoes from ~0.6s to ~0.07s. Therunning_or_healthycheck used byup --waitstill waits for the first tick, so--waitkeeps reporting a container that exits right after starting as a failure.Related issue
Fixes #14384
Changes made
pkg/compose/service_containers.go:waitDependencychecksservice_healthyandservice_completed_successfullyon entry, without waiting for a tick.running_or_healthy(used by--wait, and for dependencies of a project rebuilt from container labels) is still first checked on the first tick. It accepts a running container that has no healthcheck, so a check right after start would report a container that exits within the interval as running. If the context is already done on entry, the wait still ends through the existingctx.Done()branch without inspecting the dependency: a cancellation stays silent, and a deadline keeps its current meaning.pkg/compose/service_containers_test.go: addTestWaitDependencyFirstCheck, which usestesting/synctestto lock when the first check of an already satisfied dependency happens: after 0s forservice_healthyandservice_completed_successfully, and after exactly 500ms forrunning_or_healthywith a running container that has no healthcheck.TestWaitDependencyDeadlineandTestOptionalDependencyInspectFailureassumed that a 50ms timeout always expires before any check. They now let the check on entry find the dependency still starting, so they still cover a deadline that expires between two polls.pkg/compose/executor_start_test.go: rewrite a comment that said the wait "never" checks on entry.pkg/e2e/testdata/TestUpWithDependencyExit/compose.yaml: givedba healthcheck. Without one, the test's expectedexited (1)only won overhas no healthcheck configuredbecause the first check came 500ms after start.Testing done
make testmake e2e-composeormake e2e-compose-standalonemake lintmake fmtAI tool used (if applicable)
AI Tool:
Additional context
waitDependency.(not mandatory) A picture of a cute animal, if possible in relation to what you did