Browse code

Fixes a race condition in client events monitoring

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>

Brian Goff authored on 2016/12/16 03:07:27
Showing 1 changed files
... ...
@@ -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
 }