Karolis
Karolis

Reputation: 2959

Dealing with long requests in Unicorn + Rails app

We have a Rails app that we run on Unicorn (2 workers) and nginx. We want to integrate a 3rd party API where processing of a single request takes between 1 and 20 seconds. If we simply create a new controller that proxies to that service the entire app suffers, because it takes only 2 people to make a request to that service via our API and for 20 seconds the rest of the users can't access the rest of our app.

We're thinking about 2 solutions.

  1. Create a separate node.js server that will do all of the requests to the 3rd party API. We would only use Rails for authentication/authorization in this case, and we would redirect the requests to node via nginx using X-Accel-Redirect header (as described here http://blog.bitbucket.org/2012/08/24/segregating-services/)
  2. Replace Unicorn with Thin or Rainbow! and keep proxying in our Rails app, which could then, presumably, allow us to handle many more concurrent connections.

Which solution might we be better off? Or is there something else we could do.

I personally feel that nodes even-loop is better suited for the job here, because in option 2 we would still be blocking many threads and waiting for HTTP requests to finish and in option 1, we could be doing more requests while waiting for the slow ones to finish.

Thanks!

Upvotes: 2

Views: 1396

Answers (2)

Karolis
Karolis

Reputation: 2959

We've been using the X-Accel-Redirect solution in production for a while now and it's working great.

In nginx config under server, we have entries for external services (written in node.js in our case), e.g.

server {
  ...
  location ^~ /some-service {
    internal;
    rewrite ^/some-service/(.*)$ /$1 break;
    proxy_pass http://location-of-some-service:5000;
  }
}

In rails we authenticate and authorize the requests and when we want to pass it to some other service, in the controller we do something like

headers['X-Accel-Redirect'] = '/some-service'
render :nothing => true

Now, rails is done with processing the request and hands it back to nginx. Nginx sees the x-accel-redirect header and replays the request to the new url - /some-service which we configured to proxy to our node.js service. Unicorn and rails can now process new requests even if node.js+nginx is still processing that original request.

This way we're using Rails as our main entry point and gatekeeper of our application - that's where authentication and authorization happens. But we were able to move a lot of functionality into these smaller, standalone node.js services when that's more appropriate.

Upvotes: 1

Kashyap
Kashyap

Reputation: 4796

You can use EventMachine in your existing Rails app which would mean much less re-writing. Instead of making a net/http request to the API, you would make a EM::HttpRequest request to the API and add a callback. This is similar to node.js option but does not require a special server IMO.

Upvotes: 0

Related Questions