How to Controller (Start/Kill) a Background Process (Server App) in Ruby

how to controller (start/kill) a background process (server app) in ruby

The standard way is to use the system functions fork (to duplicate the current process), exec (to replace the current process by an executable file), and kill (to send a signal to a process to terminate it).

For example :

pid = fork do
# this code is run in the child process
# you can do anything here, like changing current directory or reopening STDOUT
exec "/path/to/executable"
end

# this code is run in the parent process
# do your stuffs

# kill it (other signals than TERM may be used, depending on the program you want
# to kill. The signal KILL will always work but the process won't be allowed
# to cleanup anything)
Process.kill "TERM", pid

# you have to wait for its termination, otherwise it will become a zombie process
# (or you can use Process.detach)
Process.wait pid

This should work on any Unix like system. Windows creates process in a different way.

How can I manage a long running process from a Rails app?

I think you should have a look at delayed_job. It should do exactly what you are after.

Rails server says port already used, how to kill that process?

Assuming you're looking to kill whatever is on port 3000 (which is what webrick normally uses), type this in your terminal to find out the PID of the process:

$ lsof -wni tcp:3000

Then, use the number in the PID column to kill the process:

$ kill -9 PID

Process.fork in Rails controller

Depends what 'processing' means.
Generally this is not going to be reliable if processing means using Rails stack - as master process freed by request may be assigned to another request by passenger and things may get wrong.
Also Passenger may shut down master process and thus Rails instance in some conditions (reducing pool of idle instances etc).

Generally this may lead to process leakage, unexpected locks, race conditions, app errors while shutdown etc.

I would suggest using workers running outside Apache/Passenger stack, e.g. using clustered BackgrounDRb or other solution (you mentioned Resque).

There is also another idea, which I currently use for cron jobs with my app. My crontab is just few wget to actions with long running tasks. You can do something similar in ruby fork with OpenURI on demand. Imagine application pinging itself by HTTP. Forked process doesn't need Rails anymore - it just accesses task page and next Passenger serves request and manages application instance for this special request.

In case Passenger kills fork's parent and thus forked process - the another Rails instance should continue to process http request.

Best practice for Rails App to run a long task in the background?

The Workling plugin allow you to schedule background tasks in a queue (they would perform the lengthy task). As of version 0.3 you can ask a worker for its status, this would allow you to display some nifty progress bars.

Another cool feature with Workling is that the asynchronous backend can be switched: you can used DelayedJobs, Spawn (classic fork), Starling...

Rails: system process won't start in rails server, but will in rails console

You're creating an orphaned process in the way that you use system() to start the ngrok process in the background:

system("ngrok start --all -log=stdout > #{ENV['APP_ROOT']}/log/ngrok.log &")

Note the & at the end of the commandline.

I'd need more details about your runtime environment to tell precisely which system policy kills the orphaned ngrok process right after starting it (which OS? if Linux, is it based on systemd? how do you start rails server, from a terminal or as a system service?).

But what's happening is this:

  • system() starts an instance of /bin/sh to interpret the commandline
  • /bin/sh starts the ngrok process in the background and terminates
  • ngrok is now "orphaned", meaning that its parent process /bin/sh is terminated, so that the ngrok process can't be wait(2)ed for
  • depending on the environment, the terminating /bin/sh may kill ngrok with a SIGHUP signal
  • or the OS re-parents ngrok, normally to the init-process (but this depends)

When you use the rails console or byebug, in both cases you're entering an interactive environment, which prepares "process groups", "session ids" and "controlling terminals" in a way suitable for interactive execution. These properties are inherited by child processes, like ngrok. This influences system policies regarding the handling of the orphaned background process.

When ngrok is started from rails server, these properties will be different (depending on the way rails server is started).

Here's a nice article about some of the OS mechanisms that might be involved: https://www.jstorimer.com/blogs/workingwithcode/7766093-daemon-processes-in-ruby

You would probably have better success by using Ruby's Process.spawn to start the background process, in combination with Process.detach in your case. This would avoid orphaning the ngrok process.



Related Topics



Leave a reply



Submit