Question

My Rails application has a route that takes a lot of time to process, which makes the entire webpage freeze.

  1. Why does this happen? Is it Rails or third-party gems which are not thread-safe?
  2. Is there any way to work around this? I'm considering using a process pool, just like a thread pool, except it is heavier, it'll take a lot of memory, but it'll be cheaper than halting the whole app.
Was it helpful?

Solution

First thing to notice, your Rails action should not be heavy-weight. When a user requests a page, you should serve the user right away.

Now, there are cases when you need the user to wait for the result, in which case, you can always use websockets, or HTTP streaming.

Now, Ruby and Rails have a problem with threads, which you can read about in "Parallelism is a Myth in Ruby."

A solution you can use in Rails, is to use servers like Unicorn, which forks as many process workers as you want, and each one will be working independent of the others, Puma for creating multi threads, etc.

Now, if you have an action which is a heavy process, you may want to delay the work to a process pool like delayed_job. You can even create a nice UI with JavaScript to fetch the status of the job and show the progress to the user. You can use a pool of tasks to be performed with RabbitMQ, where another process On the background could listen to new messages and act on them, and even give a response, etc.

Have in mind that most webservers have a client timeout, and you don't really want the user to wait for one minute or more without a response, so it's always nice to use a stream response to give some feedback right away while the action is being completed, or answer with some JavaScript code that will continue hitting the server to see how the task is being performed, or even a websocket if required.

OTHER TIPS

Rails uses a mutex lock around the entire request in the middleware stack, so a Rails process only ever takes one request at a time.

However, you can disable this by enabling the config.threadsafe! option AND using a multithreaded server, such as Puma.

Then there is the whole roadblock of using MRI which doesn't really let two threads run at the same time unless they are doing non-blocking I/O.

You would need to use a Ruby implementation that supports real threads, such as Rubinius or Jruby.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top