Process.fork in a Rails controller

We make several prototypes of the new application and noticed that one of the actions was loading forever (80-120 seconds). Since most of the processing should not happen when the page loads (we can request data via Ajax later), I thought about using Process.fork so that the page returns immediately and the processing is still going on behind the scenes. "

We use Apache with Passenger for the application.

A few things:

  • I know about delayed_jobs, resque, BJ and other gems. We use dj, and in the end we will use something similar for this. This is a temporary solution while we are prototyping.

  • I don't care about server performance. The application runs on its own server, and only a few users try to execute it.

Early tests show that this works well, but I wonder if it will be useful to use this. Will it be reliable? Does the forked process continue if the user goes to another page or closes a tab / browser? Once the plug is finished, will the process be completed on its own?

+4
source share
3 answers

Depends on what "processing" means. Generally, this will not be reliable if processing means using a Rails stack - since a master process freed up by request can be assigned to another passenger request, and everything can go wrong. Also, the Passenger can disable the master process and, thus, the Rails instance in some conditions (reducing the pool of unused instances, etc.).

Typically, this can lead to a process leak, unexpected locks, race conditions, application errors when shutting down, etc.

I would suggest using workers working outside the Apache / Passenger stack, for example. using clustered BackgrounDRb or another solution (you mentioned Resque).

There is another idea that I am currently using to work cron with my application. My crontab is just a few wget for action with long jobs. You can do something similar in an OpenURI ruby fork on request. Imagine an application pinging over HTTP. The Rails process no longer needs the Forked process β€” it just accesses the task page, and the next Passenger serves the request and manages the application instance for this special request.

If the passenger kills the parent of the fork and, therefore, the process branches, another Rails instance should continue to process the http request.

+5
source

Yes, it is reliable as long as you use a gem that has been tested and used before. Both DelayedJobs and Spawn (which I often use) have been around for quite some time and should do exactly what you expect from them.

Since the process runs in the background on your server, it should remain fine if the user closes a tab / browser that does not have client attachments. When the program finishes executing, it will terminate itself and free up memory.

You can learn more about forking on this great wiki page . As a side note, do not use the ruby ​​fork method in Rails, as this will not work well with ActiveRecord.

0
source

Just wanted to call back if google takes you here. In Passenger> v4.0 there is a way to do this using Out of Band Performance. I use it for long-term tasks such as sending emails in a Sinatra controller as follows:

 # Your app should tell Passenger about this OOB task, won't run otherwise headers['X-Passenger-Request-OOB-Work'] = "true" PhusionPassenger.on_event(:oob_work) do # The following line takes a while to run, # but won't tie up any http-serving processes mail.deliver! end 

Information can be found here: http://blog.phusion.nl/2013/01/22/phusion-passenger-4-technology-preview-out-of-band-work/

I used to try to use Process.fork and try to kill the process later; while it actually does the first part, it will not actually destroy the forked process afterwards, and the Passenger will eventually eat up all available memory (as I carefully figured out in the production system). It is impossible to program, apparently, your own life.

Hope this helps!

0
source

All Articles