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 bewait(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
How to Call Applicationcontroller Methods from Applicationhelper
Creating an Md5 Hash of a Number, String, Array, or Hash in Ruby
No Database Connection in Rails Console
Simple_Form: Remove Outer Label for an Inline Checkbox with Label
Ruby Class with Static Method Calling a Private Method
Generate a Migration File from Schema.Rb
Sending a Post Request with Net/Http
How to Do Basic Authentication Over Https in Ruby
Cucumber, Capybara and Selenium - Submitting a Form Without a Button
How to Delete All Contents of a Folder with Ruby-Rails
Possible to Alias a Belongs_To Association in Rails
How to Require a Specific Version of a Ruby Gem