Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

using Kernel#fork for backgrounding processes, pros? cons?

I'd like some thoughts on whether using fork{} to 'background' a process from a rails app is such a good idea or not...

From what I gather fork{my_method; Process#setsid} does in fact do what it's supposed to do.

1) creates another processes with a different PID

2) doesn't interrupt the calling process (e.g. it continues w/o waiting for the fork to finish)

3) executes the child until it finishes

..which is cool, but is it a good idea? What exactly is fork doing? Does it create a duplicate instance of my entire rails mongrel/passenger instance in memory? If so that would be very bad. Or, does it somehow do it without consuming a huge swath of memory.

My ultimate goal was to do away with my background daemon/queue system in favor of forking these processes (primarily sending emails) -- but if this won't save memory then it's definitely a step in the wrong direction

like image 565
jsharpe Avatar asked Oct 14 '09 18:10

jsharpe


2 Answers

The fork does make a copy of your entire process, and, depending on exactly how you are hooked up to the application server, a copy of that as well. As noted in the other discussion this is done with copy-on-write so it's tolerable. Unix is built around fork(2), after all, so it has to manage it fairly fast. Note that any partially buffered I/O, open files, and lots of other stuff are also copied, as well as the state of the program that is spring-loaded to write them out, which would be incorrect.

I have a few thoughts:

  • Are you using Action Mailer? It seems like email would be easily done with AM or by Process.popen of something. (Popen will do a fork, but it is immediately followed by an exec.)
  • immediately get rid of all that state by executing Process.exec of another ruby interpreter plus your functionality. If there is too much state to transfer or you really need to use those duplicated file descriptors, you might do something like IO#popen instead so you can send the subprocess work to do. The system will share the pages containing the text of the Ruby interpreter of the subprocess with the parent automatically.
  • in addition to the above, you might want to consider the use of the daemons gem. While your rails process is already a daemon, using the gem might make it easier to keep one background task running as a batch job server, and make it easy to start, monitor, restart if it bombs, and shut down when you do...
  • if you do exit from a fork(2)ed subprocess, use exit! instead of exit
  • having a message queue and a daemon already set up, like you do, kinda sounds like a good solution to me :-)
like image 100
DigitalRoss Avatar answered Oct 12 '22 05:10

DigitalRoss


Be aware that it will prevent you from using JRuby on Rails as fork() is not implemented (yet).

like image 30
Redbeard Avatar answered Oct 12 '22 04:10

Redbeard