Here's a bare-bones Rails 4 project I've set up to troubleshoot my problem:
https://github.com/rejacobson/rails4-streamtest
I have a route set up at /home/stream that should stream a line of text 5 times in 1 second intervals.
def stream
5.times do |n|
puts "Streaming: #{n}"
response.stream.write "Streaming: #{n+1}"
sleep 1
end
rescue IOError => e
puts 'Connection closed'
ensure
response.stream.close
end
When I run puma using tcp://, without nginx, the streaming works perfectly.
curl -N http://localhost:3000/home/stream
And I get the 5 lines streamed back, no problem.
When I introduce nginx, curl will output the first line but immediately exit after that. I do continue to see output from the puts calls on the server and logs, so I know the request is still processing in the 5.times loop.
It also doesn't throw an IOError exception like it would if the user cut the connection.
Here's what I've tried so far:
- Different combinations of nginx directives in the main conf file and the server conf.
- Changing rails settings.
- Various puma config settings.
- Setting all kinds of different headers in the controller method in the hopes that it was a caching issue.
Searching the internet has provided very little help as well.
I'm at a loss and require some direction.
Here's the output of both curl calls, with and without nginx.
Without nginx
~/projects/streamtest ▰ master ▰
ryan mirage ▰▰▰▰ curl -i -N http://192.168.1.100:3000/home/stream
HTTP/1.1 200 OK
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-UA-Compatible: chrome=1
Cache-Control: no-cache
Content-Type: text/html; charset=utf-8
Set-Cookie: request_method=GET; path=/
X-Request-Id: 9ce86358-4476-404a-97e5-769c16ec7b0c
X-Runtime: 0.978099
Transfer-Encoding: chunked
Streaming: 1Streaming: 2Streaming: 3Streaming: 4Streaming: 5
puma.stdout
Streaming: 0
Streaming: 1
Streaming: 2
Streaming: 3
Streaming: 4
[8048] 192.168.1.100 - - [14/Mar/2014 21:04:50] "GET /home/stream HTTP/1.1" 200 - 6.0661
With nginx
~/projects/streamtest ▰ master ▰
ryan mirage ▰▰▰▰ curl -i -N http://192.168.1.100:3000/home/stream
HTTP/1.1 200 OK
Server: nginx/1.4.5
Date: Sat, 15 Mar 2014 04:02:40 GMT
Content-Type: text/html; charset=utf-8
Transfer-Encoding: chunked
Connection: keep-alive
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block
X-Content-Type-Options: nosniff
X-UA-Compatible: chrome=1
ETag: "a505e0aa3b11b25301a9a704252a519a"
Cache-Control: max-age=0, private, must-revalidate
Set-Cookie: request_method=GET; path=/
X-Request-Id: 8983d199-026b-4082-a5f1-f1d6c886a3d6
X-Runtime: 0.016516
Streaming: 1
puma.stdout
Streaming: 0
[7558] 192.168.1.100 - - [14/Mar/2014 21:02:40] "GET /home/stream HTTP/1.0" 200 - 0.0214
Streaming: 1
Streaming: 2
Streaming: 3
Streaming: 4
What's interesting, and I've just noticed it, is that the location of the get request log line:
"GET /home/stream HTTP/1.0" 200
is different in each curl call, and is placed in relation to how much text is actually streamed.
Any ideas as to what's going on here? Why can't rails stream the entire thing when using nginx?