2

I have an application in RubyOnRails, proxied by a NGINX server that is behind a CDN service. The CDN has a limitation that if the response first byte does not arrive in 60 seconds, the CDN server responds:

Error 503 first byte timeout

The problem is that I do have some requests that take more than 60 seconds to be processed on the Rails side. Is there a way to hack the response, sending a few bytes before the response finish its processing? How?

Edit 1:

I know 60s is a long time and we are thinking about ways to avoid this. Still, I need a temporary solution that allows those 60s requests work. Even if I use Ajax, some ajax calls would take more than 60s and would fall into the same issue. The tcp_nopush or tcp_nodelay options did not work, I think it is because nginx is waiting the rails application response to know what headers it should send. So, maybe the solution is something that I need to hack inside the RubyOnRails request/response cycle

Daniel Cukier
  • 823
  • 1
  • 10
  • 18

1 Answers1

3

A request taking more than 60 seconds is a significant amount of time. You may want to review your application. A page load time that long could have a lot of visitors exiting your app. You may want to consider loading the data asynchronously such as with AJAX or websockets.

The time to first byte is usually applied to the headers, not the response body. The client should be receiving the headers early on. Are you sure that it is your CDN timing out the requests? NGinx will timeout your requests also. A good way to check is with curl:

curl -I -H "Host: <domain>" http://<ip of proxy>/request/uri 

(Use the real IP of your proxy, not the CDN IP)

The -I option will show you the response headers, that way you can get a good indication of what error code (if any) is being returned by nginx. You can also see if you are receiving request headers and how long it takes, as this is what tcp first byte refers to.

If you are not receiving the headers quickly, try using:

http {
tcp_nopush off; 
tcp_nodelay on; # force socket to send buffer
}

If you are getting a gateway timeout error or similar, please try the following configuration options:

http {
keepalive_timeout 300;
proxy_connect_timeout 300;
proxy_read_timeout    300;
proxy_send_timeout    300;
}
Gregory Wolf
  • 131
  • 1
  • This is good advice, especially around rethinking the architecture. If something is going to take more than a couple of seconds of computation you probably should make it asynchronous. Fir example with a message queue or similar, with the results available from a web page later. 60 seconds is longer than virtually everyone will wait for a public website, so unless this an internal only site you'll likely lose visitors. – Tim Sep 04 '16 at 00:05
  • I know 60s is a long time and we are thinking about ways to avoid this. Still, I need a temporary solution that allows those 60s requests work. Even if I use Ajax, some ajax calls would take more than 60s and would fall into the same issue. The tcp_nopush or tcp_nodelay options did not work, I think it is because nginx is waiting the rails application response to know what headers it should send. So, maybe the solution is something that I need to hack inside the RubyOnRails request/response cycle – Daniel Cukier Sep 04 '16 at 14:51