Skip to content

Commit

Permalink
Solve unordered container dependency problem
Browse files Browse the repository at this point in the history
  • Loading branch information
ubhattacharjya committed Sep 8, 2020
1 parent 6cdb042 commit 7daa534
Show file tree
Hide file tree
Showing 2 changed files with 73 additions and 1 deletion.
7 changes: 6 additions & 1 deletion agent/engine/dependencygraph/graph.go
Original file line number Diff line number Diff line change
Expand Up @@ -252,6 +252,8 @@ func verifyContainerOrderingStatusResolvable(target *apicontainer.Container, exi
return nil, nil
}

var blockedDependency *apicontainer.DependsOn

targetDependencies := target.GetDependsOn()
for _, dependency := range targetDependencies {
dependencyContainer, ok := existingContainers[dependency.ContainerName]
Expand All @@ -276,9 +278,12 @@ func verifyContainerOrderingStatusResolvable(target *apicontainer.Container, exi
}

if !resolves(target, dependencyContainer, dependency.Condition) {
return &dependency, fmt.Errorf("dependency graph: failed to resolve the container ordering dependency [%v] for target [%v]", dependencyContainer, target)
blockedDependency = &dependency
}
}
if blockedDependency != nil {
return blockedDependency, fmt.Errorf("dependency graph: failed to resolve the container ordering dependency [%v] for target [%v]", blockedDependency, target)
}
return nil, nil
}

Expand Down
67 changes: 67 additions & 0 deletions agent/engine/ordering_integ_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -433,6 +433,73 @@ func TestShutdownOrder(t *testing.T) {
waitFinished(t, finished, shutdownOrderingTimeout)
}

func TestMultipleContainerDependency(t *testing.T) {
taskEngine, done, _ := setupWithDefaultConfig(t)
defer done()

stateChangeEvents := taskEngine.StateChangeEvents()

taskArn := "testMultipleContainerDependency"
testTask := createTestTask(taskArn)

exit := createTestContainerWithImageAndName(baseImageForOS, "exit")
A := createTestContainerWithImageAndName(baseImageForOS, "A")
B := createTestContainerWithImageAndName(baseImageForOS, "B")

exit.EntryPoint = &entryPointForOS
exit.Command = []string{"exit 1"}
exit.Essential = false

A.EntryPoint = &entryPointForOS
A.Command = []string{"sleep 10"}
A.Essential = true
A.DependsOnUnsafe = []apicontainer.DependsOn{
{
ContainerName: "exit",
Condition: "SUCCESS",
},
}

B.EntryPoint = &entryPointForOS
B.Command = []string{"sleep 10"}
B.Essential = true
B.DependsOnUnsafe = []apicontainer.DependsOn{
{
ContainerName: "A",
Condition: "START",
},
{
ContainerName: "exit",
Condition: "SUCCESS",
},
}

testTask.Containers = []*apicontainer.Container{
exit,
A,
B,
}

go taskEngine.AddTask(testTask)

finished := make(chan interface{})
go func() {
// Only exit should first progress to running
verifyContainerRunningStateChange(t, taskEngine)

// Exit container should stop with exit code 1
event := <-stateChangeEvents
assert.Equal(t, event.(api.ContainerStateChange).Status, status.ContainerStopped)
assert.Equal(t, event.(api.ContainerStateChange).ContainerName, "exit")

// The task should be now stopped as dependencies of A and B are not resolved
verifyTaskIsStopped(stateChangeEvents, testTask)
close(finished)
}()

waitFinished(t, finished, orderingTimeout)
}

func waitFinished(t *testing.T, finished <-chan interface{}, duration time.Duration) {
select {
case <-finished:
Expand Down

0 comments on commit 7daa534

Please sign in to comment.