Use appropriate dependency condition for one-shot containers when running `compose up --wait`

Also add e2e tests to ensure `compose up --wait` does not get stuck forever waiting for one-shot containers

Signed-off-by: Laura Brehm <laurabrehm@hey.com>
This commit is contained in:
Laura Brehm 2022-06-17 15:11:48 +02:00
parent ab25aabfb9
commit fd8538f780
3 changed files with 73 additions and 1 deletions

View File

@ -80,7 +80,7 @@ func (s *composeService) start(ctx context.Context, projectName string, options
depends := types.DependsOnConfig{}
for _, s := range project.Services {
depends[s.Name] = types.ServiceDependency{
Condition: ServiceConditionRunningOrHealthy,
Condition: getDependencyCondition(s, project),
}
}
err = s.waitDependencies(ctx, project, depends)
@ -92,6 +92,20 @@ func (s *composeService) start(ctx context.Context, projectName string, options
return eg.Wait()
}
// getDependencyCondition checks if service is depended on by other services
// with service_completed_successfully condition, and applies that condition
// instead, or --wait will never finish waiting for one-shot containers
func getDependencyCondition(service types.ServiceConfig, project *types.Project) string {
for _, services := range project.Services {
for dependencyService, dependencyConfig := range services.DependsOn {
if dependencyService == service.Name && dependencyConfig.Condition == types.ServiceConditionCompletedSuccessfully {
return types.ServiceConditionCompletedSuccessfully
}
}
}
return ServiceConditionRunningOrHealthy
}
type containerWatchFn func(container moby.Container) error
// watchContainers uses engine events to capture container start/die and notify ContainerEventListener

View File

@ -0,0 +1,47 @@
/*
Copyright 2020 Docker Compose CLI authors
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package e2e
import (
"strings"
"testing"
"time"
"gotest.tools/v3/assert"
)
func TestUpWait(t *testing.T) {
c := NewParallelCLI(t)
const projectName = "e2e-deps-wait"
timeout := time.After(30 * time.Second)
done := make(chan bool)
go func() {
res := c.RunDockerComposeCmd(t, "-f", "fixtures/dependencies/deps-completed-successfully.yaml", "--project-name", projectName, "up", "--wait", "-d")
assert.Assert(t, strings.Contains(res.Combined(), "e2e-deps-wait-oneshot-1"), res.Combined())
done <- true
}()
select {
case <-timeout:
t.Fatal("test did not finish in time")
case <-done:
break
}
c.RunDockerComposeCmd(t, "--project-name", projectName, "down")
}

View File

@ -0,0 +1,11 @@
version: '3'
services:
oneshot:
image: ubuntu
command: echo 'hello world'
longrunning:
image: ubuntu
depends_on:
oneshot:
condition: service_completed_successfully
command: sleep infinity