Browse code

use router.Cancellable instead of direct CloseNotify

Signed-off-by: Alexander Morozov <lk4d4@docker.com>

Alexander Morozov authored on 2016/03/26 03:33:54
Showing 10 changed files
... ...
@@ -24,6 +24,6 @@ func (r *buildRouter) Routes() []router.Route {
24 24
 
25 25
 func (r *buildRouter) initRoutes() {
26 26
 	r.routes = []router.Route{
27
-		router.NewPostRoute("/build", r.postBuild),
27
+		router.Cancellable(router.NewPostRoute("/build", r.postBuild)),
28 28
 	}
29 29
 }
... ...
@@ -184,21 +184,6 @@ func (br *buildRouter) postBuild(ctx context.Context, w http.ResponseWriter, r *
184 184
 	stdout := &streamformatter.StdoutFormatter{Writer: out, StreamFormatter: sf}
185 185
 	stderr := &streamformatter.StderrFormatter{Writer: out, StreamFormatter: sf}
186 186
 
187
-	finished := make(chan struct{})
188
-	defer close(finished)
189
-	if notifier, ok := w.(http.CloseNotifier); ok {
190
-		notifyContext, cancel := context.WithCancel(ctx)
191
-		closeNotifier := notifier.CloseNotify()
192
-		go func() {
193
-			select {
194
-			case <-closeNotifier:
195
-				cancel()
196
-			case <-finished:
197
-			}
198
-		}()
199
-		ctx = notifyContext
200
-	}
201
-
202 187
 	imgID, err := br.backend.Build(ctx, buildOptions,
203 188
 		builder.DockerIgnoreContext{ModifiableContext: buildContext},
204 189
 		stdout, stderr, out)
... ...
@@ -4,6 +4,8 @@ import (
4 4
 	"io"
5 5
 	"time"
6 6
 
7
+	"golang.org/x/net/context"
8
+
7 9
 	"github.com/docker/docker/api/types/backend"
8 10
 	"github.com/docker/docker/pkg/archive"
9 11
 	"github.com/docker/docker/pkg/version"
... ...
@@ -49,8 +51,8 @@ type stateBackend interface {
49 49
 type monitorBackend interface {
50 50
 	ContainerChanges(name string) ([]archive.Change, error)
51 51
 	ContainerInspect(name string, size bool, version version.Version) (interface{}, error)
52
-	ContainerLogs(name string, config *backend.ContainerLogsConfig, started chan struct{}) error
53
-	ContainerStats(name string, config *backend.ContainerStatsConfig) error
52
+	ContainerLogs(ctx context.Context, name string, config *backend.ContainerLogsConfig, started chan struct{}) error
53
+	ContainerStats(ctx context.Context, name string, config *backend.ContainerStatsConfig) error
54 54
 	ContainerTop(name string, psArgs string) (*types.ContainerProcessList, error)
55 55
 
56 56
 	Containers(config *types.ContainerListOptions) ([]*types.Container, error)
... ...
@@ -33,8 +33,8 @@ func (r *containerRouter) initRoutes() {
33 33
 		router.NewGetRoute("/containers/{name:.*}/changes", r.getContainersChanges),
34 34
 		router.NewGetRoute("/containers/{name:.*}/json", r.getContainersByName),
35 35
 		router.NewGetRoute("/containers/{name:.*}/top", r.getContainersTop),
36
-		router.NewGetRoute("/containers/{name:.*}/logs", r.getContainersLogs),
37
-		router.NewGetRoute("/containers/{name:.*}/stats", r.getContainersStats),
36
+		router.Cancellable(router.NewGetRoute("/containers/{name:.*}/logs", r.getContainersLogs)),
37
+		router.Cancellable(router.NewGetRoute("/containers/{name:.*}/stats", r.getContainersStats)),
38 38
 		router.NewGetRoute("/containers/{name:.*}/attach/ws", r.wsContainersAttach),
39 39
 		router.NewGetRoute("/exec/{id:.*}/json", r.getExecByID),
40 40
 		router.NewGetRoute("/containers/{name:.*}/archive", r.getContainersArchive),
... ...
@@ -67,19 +67,13 @@ func (s *containerRouter) getContainersStats(ctx context.Context, w http.Respons
67 67
 		w.Header().Set("Content-Type", "application/json")
68 68
 	}
69 69
 
70
-	var closeNotifier <-chan bool
71
-	if notifier, ok := w.(http.CloseNotifier); ok {
72
-		closeNotifier = notifier.CloseNotify()
73
-	}
74
-
75 70
 	config := &backend.ContainerStatsConfig{
76 71
 		Stream:    stream,
77 72
 		OutStream: w,
78
-		Stop:      closeNotifier,
79 73
 		Version:   string(httputils.VersionFromContext(ctx)),
80 74
 	}
81 75
 
82
-	return s.backend.ContainerStats(vars["name"], config)
76
+	return s.backend.ContainerStats(ctx, vars["name"], config)
83 77
 }
84 78
 
85 79
 func (s *containerRouter) getContainersLogs(ctx context.Context, w http.ResponseWriter, r *http.Request, vars map[string]string) error {
... ...
@@ -97,11 +91,6 @@ func (s *containerRouter) getContainersLogs(ctx context.Context, w http.Response
97 97
 		return fmt.Errorf("Bad parameters: you must choose at least one stream")
98 98
 	}
99 99
 
100
-	var closeNotifier <-chan bool
101
-	if notifier, ok := w.(http.CloseNotifier); ok {
102
-		closeNotifier = notifier.CloseNotify()
103
-	}
104
-
105 100
 	containerName := vars["name"]
106 101
 	logsConfig := &backend.ContainerLogsConfig{
107 102
 		ContainerLogsOptions: types.ContainerLogsOptions{
... ...
@@ -113,11 +102,10 @@ func (s *containerRouter) getContainersLogs(ctx context.Context, w http.Response
113 113
 			ShowStderr: stderr,
114 114
 		},
115 115
 		OutStream: w,
116
-		Stop:      closeNotifier,
117 116
 	}
118 117
 
119 118
 	chStarted := make(chan struct{})
120
-	if err := s.backend.ContainerLogs(containerName, logsConfig, chStarted); err != nil {
119
+	if err := s.backend.ContainerLogs(ctx, containerName, logsConfig, chStarted); err != nil {
121 120
 		select {
122 121
 		case <-chStarted:
123 122
 			// The client may be expecting all of the data we're sending to
... ...
@@ -18,7 +18,7 @@ func NewRouter(b Backend) router.Router {
18 18
 	r.routes = []router.Route{
19 19
 		router.NewOptionsRoute("/{anyroute:.*}", optionsHandler),
20 20
 		router.NewGetRoute("/_ping", pingHandler),
21
-		router.NewGetRoute("/events", r.getEvents),
21
+		router.Cancellable(router.NewGetRoute("/events", r.getEvents)),
22 22
 		router.NewGetRoute("/info", r.getInfo),
23 23
 		router.NewGetRoute("/version", r.getVersion),
24 24
 		router.NewPostRoute("/auth", r.postAuth),
... ...
@@ -83,11 +83,6 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
83 83
 		}
84 84
 	}
85 85
 
86
-	var closeNotify <-chan bool
87
-	if closeNotifier, ok := w.(http.CloseNotifier); ok {
88
-		closeNotify = closeNotifier.CloseNotify()
89
-	}
90
-
91 86
 	for {
92 87
 		select {
93 88
 		case ev := <-l:
... ...
@@ -101,8 +96,8 @@ func (s *systemRouter) getEvents(ctx context.Context, w http.ResponseWriter, r *
101 101
 			}
102 102
 		case <-timer.C:
103 103
 			return nil
104
-		case <-closeNotify:
105
-			logrus.Debug("Client disconnected, stop sending events")
104
+		case <-ctx.Done():
105
+			logrus.Debug("Client context cancelled, stop sending events")
106 106
 			return nil
107 107
 		}
108 108
 	}
... ...
@@ -31,7 +31,6 @@ type ContainerAttachConfig struct {
31 31
 type ContainerLogsConfig struct {
32 32
 	types.ContainerLogsOptions
33 33
 	OutStream io.Writer
34
-	Stop      <-chan bool
35 34
 }
36 35
 
37 36
 // ContainerStatsConfig holds information for configuring the runtime
... ...
@@ -39,7 +38,6 @@ type ContainerLogsConfig struct {
39 39
 type ContainerStatsConfig struct {
40 40
 	Stream    bool
41 41
 	OutStream io.Writer
42
-	Stop      <-chan bool
43 42
 	Version   string
44 43
 }
45 44
 
... ...
@@ -6,6 +6,8 @@ import (
6 6
 	"strconv"
7 7
 	"time"
8 8
 
9
+	"golang.org/x/net/context"
10
+
9 11
 	"github.com/Sirupsen/logrus"
10 12
 	"github.com/docker/docker/api/types/backend"
11 13
 	"github.com/docker/docker/container"
... ...
@@ -19,7 +21,7 @@ import (
19 19
 
20 20
 // ContainerLogs hooks up a container's stdout and stderr streams
21 21
 // configured with the given struct.
22
-func (daemon *Daemon) ContainerLogs(containerName string, config *backend.ContainerLogsConfig, started chan struct{}) error {
22
+func (daemon *Daemon) ContainerLogs(ctx context.Context, containerName string, config *backend.ContainerLogsConfig, started chan struct{}) error {
23 23
 	container, err := daemon.GetContainer(containerName)
24 24
 	if err != nil {
25 25
 		return err
... ...
@@ -78,7 +80,7 @@ func (daemon *Daemon) ContainerLogs(containerName string, config *backend.Contai
78 78
 		case err := <-logs.Err:
79 79
 			logrus.Errorf("Error streaming logs: %v", err)
80 80
 			return nil
81
-		case <-config.Stop:
81
+		case <-ctx.Done():
82 82
 			logs.Close()
83 83
 			return nil
84 84
 		case msg, ok := <-logs.Msg:
... ...
@@ -5,6 +5,8 @@ import (
5 5
 	"errors"
6 6
 	"runtime"
7 7
 
8
+	"golang.org/x/net/context"
9
+
8 10
 	"github.com/docker/docker/api/types/backend"
9 11
 	"github.com/docker/docker/pkg/ioutils"
10 12
 	"github.com/docker/docker/pkg/version"
... ...
@@ -14,7 +16,7 @@ import (
14 14
 
15 15
 // ContainerStats writes information about the container to the stream
16 16
 // given in the config object.
17
-func (daemon *Daemon) ContainerStats(prefixOrName string, config *backend.ContainerStatsConfig) error {
17
+func (daemon *Daemon) ContainerStats(ctx context.Context, prefixOrName string, config *backend.ContainerStatsConfig) error {
18 18
 	if runtime.GOOS == "windows" {
19 19
 		return errors.New("Windows does not support stats")
20 20
 	}
... ...
@@ -114,7 +116,7 @@ func (daemon *Daemon) ContainerStats(prefixOrName string, config *backend.Contai
114 114
 			if !config.Stream {
115 115
 				return nil
116 116
 			}
117
-		case <-config.Stop:
117
+		case <-ctx.Done():
118 118
 			return nil
119 119
 		}
120 120
 	}