Browse code

Logs with follow=1 immediately send HTTP response

Signed-off-by: Anthony Baire <Anthony.Baire@irisa.fr>
Signed-off-by: Arnaud Porterie <arnaud.porterie@docker.com>

Anthony Baire authored on 2015/04/24 07:08:41
Showing 2 changed files
... ...
@@ -129,6 +129,11 @@ func (daemon *Daemon) ContainerLogs(name string, config *ContainerLogsConfig) er
129 129
 		errors := make(chan error, 2)
130 130
 		wg := sync.WaitGroup{}
131 131
 
132
+		// write an empty chunk of data (this is to ensure that the
133
+		// HTTP Response is sent immediatly, even if the container has
134
+		// not yet produced any data)
135
+		outStream.Write(nil)
136
+
132 137
 		if config.UseStdout {
133 138
 			wg.Add(1)
134 139
 			stdoutPipe := container.StdoutLogPipe()
... ...
@@ -60,3 +60,25 @@ func (s *DockerSuite) TestLogsApiNoStdoutNorStderr(c *check.C) {
60 60
 		c.Fatalf("Expected %s, got %s", expected, string(body[:]))
61 61
 	}
62 62
 }
63
+
64
+// Regression test for #12704
65
+func (s *DockerSuite) TestLogsApiFollowEmptyOutput(c *check.C) {
66
+	defer deleteAllContainers()
67
+	name := "logs_test"
68
+	t0 := time.Now()
69
+	runCmd := exec.Command(dockerBinary, "run", "-d", "-t", "--name", name, "busybox", "sleep", "10")
70
+	if out, _, err := runCommandWithOutput(runCmd); err != nil {
71
+		c.Fatal(out, err)
72
+	}
73
+
74
+	_, body, err := sockRequestRaw("GET", fmt.Sprintf("/containers/%s/logs?follow=1&stdout=1&stderr=1&tail=all", name), bytes.NewBuffer(nil), "")
75
+	t1 := time.Now()
76
+	body.Close()
77
+	if err != nil {
78
+		c.Fatal(err)
79
+	}
80
+	elapsed := t1.Sub(t0).Seconds()
81
+	if elapsed > 5.0 {
82
+		c.Fatalf("HTTP response was not immediate (elapsed %.1fs)", elapsed)
83
+	}
84
+}