In cases where there is high latency (ie, not-local network)
`waitExitOrRemoved` was not receiving events for short-lived containers.
This caused the client to hang while waiting for a notification that the
container has stopped.
This happens because `client.Events()` returns immediately and spins a
goroutine up to process events. The problem here is it returns before
the request to the events endpoint is even made.
Even without high-latency issues, there is no guarantee that the
goroutine is even scheduled by the time the function returns.
Signed-off-by: Brian Goff <cpuguy83@gmail.com>
| ... | ... |
@@ -22,17 +22,20 @@ func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-c |
| 22 | 22 |
messages := make(chan events.Message) |
| 23 | 23 |
errs := make(chan error, 1) |
| 24 | 24 |
|
| 25 |
+ started := make(chan struct{})
|
|
| 25 | 26 |
go func() {
|
| 26 | 27 |
defer close(errs) |
| 27 | 28 |
|
| 28 | 29 |
query, err := buildEventsQueryParams(cli.version, options) |
| 29 | 30 |
if err != nil {
|
| 31 |
+ close(started) |
|
| 30 | 32 |
errs <- err |
| 31 | 33 |
return |
| 32 | 34 |
} |
| 33 | 35 |
|
| 34 | 36 |
resp, err := cli.get(ctx, "/events", query, nil) |
| 35 | 37 |
if err != nil {
|
| 38 |
+ close(started) |
|
| 36 | 39 |
errs <- err |
| 37 | 40 |
return |
| 38 | 41 |
} |
| ... | ... |
@@ -40,6 +43,7 @@ func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-c |
| 40 | 40 |
|
| 41 | 41 |
decoder := json.NewDecoder(resp.body) |
| 42 | 42 |
|
| 43 |
+ close(started) |
|
| 43 | 44 |
for {
|
| 44 | 45 |
select {
|
| 45 | 46 |
case <-ctx.Done(): |
| ... | ... |
@@ -61,6 +65,7 @@ func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-c |
| 61 | 61 |
} |
| 62 | 62 |
} |
| 63 | 63 |
}() |
| 64 |
+ <-started |
|
| 64 | 65 |
|
| 65 | 66 |
return messages, errs |
| 66 | 67 |
} |