Async Requests

Wolox Engineering
Wolox
Published in
3 min readJun 16, 2016

One common issue we face at the time of building APIs with Rails is making requests that depend on an external service’s response. Let’s say we have to log a user into our system and the login process goes as follows:

Although this is a valid way of logging in a user, it has several drawbacks:

  • Response time now depends on an external resource we do not control
  • If the external server is slow, our server might suffer from a DOS (Denial of Service) without even having a malicious client trying to force it.
  • Our entire application will seem to be slow because threads will be consuming most of their time in this slow request.

How can we solve this problem in a language that does not allow async operations?

At Wolox, we decided to tackle this issue with the following architecture:

  1. The client makes a request to our server.
  2. The server queues a task to process the requested action and returns a job_id to the client.
  3. While the task is being processed, our endpoint returns 202 (Accepted) each time the client requests the job’s status.
  4. Once the job is processed, the server responds with the job result.

With this approach, our server’s response time doesn’t depend on external resources we do not control. Hence, we don’t have the drawbacks presented in the previous section. On the other hand, this requires the client to implement a busy-waiting loop, adding complexity to their code.

In order to take this approach into action, we developed the async_request gem. In order to execute an async task, you need only to follow these steps:

  • Add the gem ‘async_request’ to your Gemfile.
  • Include AsyncRequest::ApplicationHelper in the controller you want to use this gem.
  • Implement a ruby class that responds to execute() with any number of arguments
  • Queue your task by executing execute_async(YourRubyClass, arg1, arg2, arg3, …)
  • execute_async will return an id. With that id, you can build the url the client can use to get the job’s status: async_request.job_url(id)

Status and Next Steps

The gem is in its first version. We’d like to add the following features:

  • Secure comparison for job ids in the jobs controller
  • Add a js file that provides exponential back-off for web clients
  • Schedule a task that deletes old jobs

You can check our backlog by visiting the gem’s issues page. Feel free to fork and pull request new features.

See also: In the End I Did It My Way

Matias De Santi @mdsanti (matias.desanti@wolox.com.ar)

www.wolox.com.ar

--

--