Подтвердить что ты не робот

Rails 4, Puma, Nginx - ActionController:: Live Streaming умирает после отправки первого фрагмента

Здесь проект Rails 4, который я создал для устранения проблемы:

https://github.com/rejacobson/rails4-streamtest

У меня есть маршрут, настроенный в /home/stream, который должен поток строки 5 раз с интервалом в 1 секунду.

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

Когда я запускаю puma с помощью tcp://, без nginx потоковая передача работает отлично.

curl -N http://localhost:3000/home/stream

И я получаю 5 строк, переданных обратно, без проблем.

Когда я ввожу nginx, curl выводит первую строку, но сразу же выйдет после этого. Я продолжаю видеть вывод из вызовов puts на сервере и журналов, поэтому я знаю, что запрос все еще обрабатывается в цикле 5.times.

Он также не генерирует исключение IOError, как если бы пользователь отключил соединение.

Вот что я пробовал до сих пор:

  • Различные комбинации директив nginx в основном файле conf и сервер conf.
  • Изменение настроек рельсов.
  • Различные настройки конфигурации puma.
  • Настройка всех типов заголовков в методе контроллера в надежде, что это проблема кэширования.

Поиск в Интернете также очень мало помог.

Я затрудняюсь и требую определенного направления.

Здесь вывод обоих вызовов curl, с nginx и без него.

Без 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

С 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

Что интересно, и я только что заметил это, это то, что местоположение строки журнала запроса запроса:

"GET/home/stream HTTP/1.0" 200

отличается в каждом вызове curl и помещается в зависимости от того, сколько текста фактически передано.

Любые идеи относительно того, что здесь происходит? Почему рельсы не могут передавать всю вещь при использовании nginx?

4b9b3361

Ответ 1

решаемые

Оказывается, все, что мне нужно, это эта строка в моей директиве location, чтобы получить потоковое управление через nginx:

proxy_http_version 1.1;

Я обнаружил это исправление при исследовании директивы keepalive в восходящем модуле nginx:

http://nginx.org/en/docs/http/ngx_http_upstream_module.html#keepalive

Этот фрагмент текста, в частности, сказал мне:

For HTTP, the proxy_http_version directive should be set to "1.1" and the "Connection" header field should be cleared:

upstream http_backend {
    server 127.0.0.1:8080;

    keepalive 16;
}

server {
    ...

    location /http/ {
        proxy_pass http://http_backend;
        proxy_http_version 1.1;
        proxy_set_header Connection "";
        ...
    }
}

Кажется, что nginx по умолчанию, proxy_http_version 1.0;

И согласно Википедии, http://en.wikipedia.org/wiki/Hypertext_Transfer_Protocol

В HTTP/1.1 введено кодированное кодирование передачи, позволяющее потоку передавать потоковые потоки, а не буферизировать содержимое на постоянных соединениях.

Так была моя проблема.

TIL