-
Notifications
You must be signed in to change notification settings - Fork 18.7k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Enhancement: allow parallel stop, pause, unpause #24761
Conversation
defer waitAll.Done() | ||
defer atomic.AddInt32(&count, -1) | ||
if err := dockerCli.Client().ContainerStop(ctx, toStop, &timeout); err != nil { | ||
errs = append(errs, err.Error()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Need a mutex for errs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I almost forget my PR. You're right, thanks @AkihiroSuda 😄
9225796
to
8553f47
Compare
Append a commit from @abhinavdahiya, thanks again for his help! 😄 |
|
||
var maxParallel int32 = 1000 | ||
//A buffered channel can be used like a semaphore, for instance to limit throughput. https://golang.org/doc/effective_go.html#channels | ||
var sem = make(chan int, maxParallel) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: chan struct{}
7670dba
to
08be7c6
Compare
08be7c6
to
a18fe6e
Compare
@tonistiigi I've made some updates since your last comments, what do you think of this? |
a18fe6e
to
c71bc5a
Compare
@tonistiigi Updated as per your suggestion, PTAL. Thanks 😄 |
What's current status? ping @tonistiigi @vdemeester @cpuguy83 |
Design SGTM @vdemeester WDYT? |
Design LGTM too 👼 |
waitAll.Done() | ||
}() | ||
|
||
var maxParallel int32 = 50 |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nit: const, also move to the beginning of the function
c71bc5a
to
5b242f2
Compare
@tonistiigi Updated, PTAL. |
LGTM 🐸 |
5b242f2
to
32ecb67
Compare
ping @tonistiigi |
/cc @dnephin |
output[container] <- err | ||
} else { | ||
output[container] <- nil | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
No reason to check err != nil
here. You're also doing the same action in both branches, just send directly to the channel:
err := ...
output[container] <- err
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correct 👍
I like the idea, I left some comments on the code. I also wonder if it would make sense to make this more generic. I suspect we could re-use this for other operations as well (pause/unpause comes to mind). We did something similar in Compose. Maybe something like: const maxParallel int32 = 50
type operation func(ctx context.Context, string id)
func ParallelOperation(ctx context.Context, args []string, op operation) ([]string, []error) {
var waitAll sync.WaitGroup
var errs []error
var result []string
output := map[string]chan error{}
var sem = make(chan struct{}, maxParallel)
waitAll.Add(len(args))
for _, arg := range args {
sem <- struct{}{} // Wait for active queue sem to drain.
go func(arg string) {
defer waitAll.Done()
output[arg] <- op(ctx, arg)
<- sem
}(arg)
waitAll.Wait()
for _, arg := range args {
err = <- output[arg]
if err != nil {
errs = append(errs, err)
} else {
result = append(result, arg)
}
}
return result, errs
} (the timeout can be passed as a closure) |
nit: +1(non-binding) for @dnephin 's suggestion, and it'd be better if |
I'm also +1 on @dnephin 's non-binding suggestion 😄 . I had the plan of add parallel operations on other command, but thought it would be better that we finish this first as an example implementation so that we can do the last quickly. I will make some modifications first as per @dnephin 's suggestions. |
89b3505
to
32f1b7c
Compare
@@ -34,8 +34,11 @@ func runPause(dockerCli *command.DockerCli, opts *pauseOptions) error { | |||
ctx := context.Background() | |||
|
|||
var errs []string | |||
errChan := parallelOperation(ctx, opts.containers, func(ctx context.Context, id string) error { | |||
return dockerCli.Client().ContainerPause(ctx, id) | |||
}) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Minor nit: I think you can just pass dockerCli.Client().ContainerPause
directly as the last argument, since it already has the right signature
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, right! 👍
LGTM |
Stop multiple containers in parallel to speed up stop process, allow maximum 50 parallel stops. Signed-off-by: Abhinav Dahiya <abhinavdtu2012@gmail.com> Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
Support parallel pause/unpause Signed-off-by: Zhang Wei <zhangwei555@huawei.com>
1e87404
to
f1dda43
Compare
Parallel start bring a failed test case, remove that first. Let's focus on parallel stop/pause/unpause first. |
LGTM 🐸 |
@dnephin latest version LGTY? |
LGTM |
Thanks @WeiZhang555! |
Enhancement: allow parallel stop, pause, unpause
Fixes #24724
Stop multiple containers in parallel to speed up stop process, allow
maximum 50 parallel stops.
Signed-off-by: Zhang Wei zhangwei555@huawei.com