Rake task for running a server in an independent thread then killing the thread when the task is complete? - ruby

How do I launch a thread within a rake task then kill the tread when the task is complete.
Essentially I am writing a rake task to test a jekyll site. I would like be able to launch the server, do some other tasks and then destroy the thread when the task is complete. Here is what I have thus far:
task :test_site do
`ejekyll --server`
`git -Xdn`
if agree( "Clean all ignored files?")
git -Xdf
end
end
but unfortunately the only way I know of to stop the jekyll --server is to use ctrl c. I would be happy to hear of a way to stop a jekyll --server in a manor which does not exit the rake task but please just comment as the question is specifically asking about threading and rake tasks.

You want Process.spawn, not a thread. It's a new process, not a thread of execution within an existing process. You get the PID back, so just send Process.kill(:QUIT, pid) or whatever method you want to use to kill the spawned processed.
pid = Process.spawn(
"ejekyll", "--server",
out: "/dev/null",
err: "/dev/null"
)
# you may need to add a short sleep() here
# other stuff
Process.kill(:QUIT, pid) && Process.wait
If ejekyll has a command line option to run in the foreground, it would be better to use that, otherwise if it self-daemonizes you need to know where it stores its PID file, in order to identify and kill the daemon.

Related

why rake tasks are not executing using and operator?

I have a rake task :
task :kill_process do
system %q(ps -ef | awk '{if($8~"java" || $8~"glassfish" || $8~"ruby" || $8~"god" || $8~"couch"){printf("Killing : %s \n",$2);{system("kill -9 "$2)};}}')
end
This is basically killing processes. And this task is a part of another rake task :
desc "stop the entire system"
task :stop => [...., :kill_process]
There's another task:
desc "start the entire system"
task :start => [....]
When I am doing rake stop && rake start
stop task is executed successfully. but rake start is not executing.
If i execute both tasks separately, then it works fine. but not in rake stop && rake start
What will be better to use here exec function or system or any other, please suggest me.
My only requirement is to kill these mentioned processes at the end of rake stop. But also it should not effect other things like rake stop && rake start should work fine.
As mentioned in the comments, the exit code is 137 which evaluates to false and therefore the other part of the && does not get executed. The reason for this is probably kill -9.
There are a few options now.
Return 0 from your rake task, something like exit(0)
Don't use kill -9
Create restart command which does execute stop and start but without logically depending on each other (&&).
Exit code 137 indicates that a process has received a SIGKILL signal and was thus killed from the outside.
This happens since a Rake task is also executed by Ruby. As such, your stop task is sending a SIGKILL to its own process too (along with all other Ruby processes on the system). Now, since you have specified that you only want to execute the rake start process if the previous process was successful (i.e. had a exit code of 0), your shell doesn't start the rake task.
To quickly fix this, you can instead run rake stop; rake start, i.e run the two processes regardless of their individual exit codes (by default).
However, a better idea would probably to make your stop task more explicit and only kill the specific processes you need rather than everything in sight which looks slightly like a related process. This will likely result in a more stable system overall too when you don't kill potentially unrelated processes all the time.

How can I create a monit process for a Ruby program?

I have these rake tasks that will occasionally fail. I want to use monit to monitor them and to restart them if necessary.
I have read the other ruby/monit threads on StackOverflow. My case is different in that these programs require my Rails environment in order to work. That's why I have them as rake tasks now.
Here is one of the tasks I need to monitor, in it's entirety:
task(process_updates: :environment) do
`echo "#{Process.pid}" > #{Rails.root}/log/process_alerts.pid`
`echo "#{Process.ppid}" > #{Rails.root}/log/process_alerts.ppid`
SynchronizationService::process_alerts
end
My question is, do I leave this as a rake task, since SynchronizationService::process_alerts requires the Rails environment to work? Or is there some other wrapper I should invoke and then just run some *.rb file?
Monit can check for running pid, since you're creating pid when you run task you can create a monit config which should look something like this:
check process alerts with pidfile RAILSROOT/log/process_alerts.pid
start program = "cd PATH_TO_APP; rake YOURTASK" with timeout 120 seconds
alert your#mail.com on { nonexist, timeout }
Of course RAILSROOT, PATH_TO_APP, YOURTASK should correspond to your paths/rake task.
Monit then will check for running process in system using the pidfile value and will start the process using start program command if it can't find running process.

How do I spawn a new process to do a task in Ruby?

I would like to write a Ruby script that runs a daemon Ruby process, so that I can do something like the following:
$ task start
Started...
# start a daemon to do useful work; don't block
# Some time later:
$ task end
Finished.
What's the best way to go about this?
Use the Process.daemon method when you want your process to detach from the terminal and stop being able to send output. To end the process, you will have to send it a signal. Most programs handle this by using a file that contains the PID.

Spawn a background process in Ruby

I'm writing a ruby bootstrapping script for a school project, and part of this bootstrapping process is to start a couple of background processes (which are written and function properly). What I'd like to do is something along the lines of:
`/path/to/daemon1 &`
`/path/to/daemon2 &`
`/path/to/daemon3 &`
However, that blocks on the first call to execute daemon1. I've seen references to a Process.spawn method, but that seems to be a 1.9+ feature, and I'm limited to Ruby 1.8.
I've also tried to execute these daemons from different threads, but I'd like my bootstrap script to be able to exit.
So how can I start these background processes so that my bootstrap script doesn't block and can exit (but still have the daemons running in the background)?
As long as you are working on a POSIX OS you can use fork and exec.
fork = Create a subprocess
exec = Replace current process with another process
You then need to inform that your main-process is not interested in the created subprocesses via Process.detach.
job1 = fork do
exec "/path/to/daemon01"
end
Process.detach(job1)
...
better way to pseudo-deamonize:
`((/path/to/deamon1 &)&)`
will drop the process into it's own shell.
best way to actually daemonize:
`service daemon1 start`
and make sure the server/user has permission to start the actual daemon. check out 'deamonize' tool for linux to set up your deamon.

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

i'm trying to set up a server for integration tests (specs actually) via ruby and can't figure out how to control the process.
so, what i'm trying to do is:
run a rake task for my gem that executes the integration specs
the task needs to first start a server (i use webrick) and then run the specs
after executing the specs it should kill the webrick so i'm not left with some unused background process
webrick is not a requirement, but it's included in the ruby standard library so being able to use it would be great.
hope anyone is able to help!
ps. i'm running on linux, so having this work for windows is not my main priority (right now).
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.
I just had to do something similar and this is what I came up with. #Michael Witrant's answer got me started, but I changed some things like using Process.spawn instead of fork (newer and better).
# start spawns a process and returns the pid of the process
def start(exe)
puts "Starting #{exe}"
pid = spawn(exe)
# need to detach to avoid daemon processes: http://www.ruby-doc.org/core-2.1.3/Process.html#method-c-detach
Process.detach(pid)
return pid
end
# This will kill off all the programs we started
def killall(pids)
pids.each do |pid|
puts "Killing #{pid}"
# 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)
begin
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
rescue => ex
puts "ERROR: Couldn't kill #{pid}. #{ex.class}=#{ex.message}"
end
end
end
# Now we can start processes and keep the pids for killing them later
pids = []
pids << start('./someprogram')
# Do whatever you want here, run your tests, etc.
# When you're done, be sure to kill of the processes you spawned
killall(pids)
That's about all she wrote, give it a try and let me know how it works.
I have tried fork, but it has kind of problems when ActiveRecord is involved in both the processes. I would suggest Spawn plugin (http://github.com/tra/spawn). It does fork only but takes care of ActiveRecord.

Resources