From bcb7147ae5cff5f3a8d8186a46a6cec33dd49cd3 Mon Sep 17 00:00:00 2001 From: Brian Goff Date: Thu, 15 Dec 2016 13:07:27 -0500 Subject: [PATCH] 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 --- events.go | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/events.go b/events.go index c154f7dcf9..af47aefa74 100644 --- a/events.go +++ b/events.go @@ -22,17 +22,20 @@ func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-c messages := make(chan events.Message) errs := make(chan error, 1) + started := make(chan struct{}) go func() { defer close(errs) query, err := buildEventsQueryParams(cli.version, options) if err != nil { + close(started) errs <- err return } resp, err := cli.get(ctx, "/events", query, nil) if err != nil { + close(started) errs <- err return } @@ -40,6 +43,7 @@ func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-c decoder := json.NewDecoder(resp.body) + close(started) for { select { case <-ctx.Done(): @@ -61,6 +65,7 @@ func (cli *Client) Events(ctx context.Context, options types.EventsOptions) (<-c } } }() + <-started return messages, errs }