how do i run an asynchronous loop in ruby? - ruby

I need to execute a process that runs several admin system commands. I want to keep the sudo timestamp current while it runs in case the process run too long.
i have the following code, but it does not seem to work.
sudo_keep_alive = Thread.start do
def sudo
sleep 5.minutes
`sudo -v`
sudo
end
sudo
end
at_exit do
sudo_keep_alive.kill
end
Is there a convention for this?
UPDATE
The reason i cannot run the script has root, is there are other system commands the script runs that cannot run as root. Each command needs to be responsible for running it's own admin commands. The script can potentially take a considerable amount of time to run, so i simply wanted to keep the sudo timestamp fresh in the event a command needs it.

To answer your other question, there is a better way to run an asynchronous loop.
By using head-tail recursion (def sudo; do_something; sudo; end) you risk running into a SystemStackError at around 10000 calls (see How does your favorite language handle deep recursion? ).
Instead, just use a regular old ruby loop.
Thread::new do
loop do
sleep 300 # 5.minutes is not base ruby, it comes from ActiveSupport
call_my_function
end
end
As mentioned by David Unric, there is no need to kill the thread using at_exit, as your main process will automatically kill any active threads when it finishes.

Scrap all this and execute your ruby script as root instead.
$ sudo ruby myscript.rb

Related

Ruby running two scripts with mulithreading

So I'm trying to have my ruby (no rails) application be run with a single call from the terminal i.e. 'ruby run.rb'. However I have two scripts that need to be run, app.rb and app2.rb, the issue is, both these scripts don't finish - they keep on being run so as to keep the system running, this means that one of the scripts never gets run - it calls the first script (app.rb) and never the second (app2.rb) these scripts need to be run concurrently!
It does work when I open another command line and just run one script in each however.
I have tried:
def runApp
system("ruby app.rb")
end
def runApp2
system("ruby app2.rb")
end
t1 = Thread.new{runApp()}
t2 = Thread.new{runApp2()}
t1.join
t2.join
However this will only run the first thread (the one running app.rb) because this is being constantly run. Any ideas how it can also run the second thread concurrently?
:EDIT: One of the scripts is using the Sinatra gem, the other also calls one of its functions every ten seconds.
So one possible solution I've found is
system("ruby app.rb & ruby app2.rb")
This only works however if running from linux I think however so I would still appreciate any further solutions.
According to the documentation you can do it like this:
threads = []
threads << Thread.new{runApp()}
threads << Thread.new{runApp2()}
threads.each { |thr| thr.join }
I guess this works because each is parallel.

Running bash script from ruby not producing the correct pid

I am developing a ruby framework to run different jobs and one of the things that I need to do is to know when these jobs have ended in order to used their outputs and organize everything. I have been using it with no problem but some colegues are starting to use it in different system and something really odd is happening. What I do is run the commands using
i,o,e,t = Open3.popen3(job.get_cmd)
p = t.pid
and later I check if the job has ended like this:
begin
Process.getpgid(p)
rescue Errno::ESRCH
# The process ended
end
It works perfectly in the system I am running (Scientifi linux 6) but when a friend of mine started running on Ubuntu 14.04 (using ruby 1.9.3p484) and the command is a concatenation of commands such as cmd1 && cmd2 && cmd3 each command is run at the same time by the system, not one after the other, and the pid returned by t.pid is neither of the pids of the different processes being run.
I modified the code and instead of running the concatenation of cammands it creates a script with all the command inside the command called from popen3 is just Open3.popen3("./script.sh") but the behaviour is the same... All the commands are run at the same time and the pid that ruby knows is not any of the processes pid...
I am not sure if this is something ruby related but since running that script.sh by hand behaves as expected, running one command after the other, it seems that either ruby is not launching the process accordingly or the system is not reading the process as it should. Do you know what might be happening?
Thanks a lot!
EDIT:
The command being run looks like this
./myFit.exe h vlq.config &> output_h.txt && ./myFit.exe d vlq.config &> output_d.txt && ./myFit.exe p vlq.config &> output_p.txt
This command, if run by hand and not inside the ruby script runs perfectly, exactly this command. When run from the ruby script it runs at the same time all the myFit.exe executions (but I want them to be run withh && becasue I want them running if the previous works fine). Myfit.exe is a tool which makes a fit, is not a system command. Again, this command, if run by hand runs perfeclty.

Ruby Process.daemon: turning on/off

I am trying to daemonize a Ruby script, running on 2.1.1.
My daemon part of the code is like this:
case ARGV[0]
when "-start"
puts "TweetSearcher started."
Process.daemon
when "-stop"
Process.kill(9,Process.pid)
else
puts "Lacks arguments. Use -start/-stop"
abort
end
However, it looks like that the Process.kill(9,Process.pid) is not killing what I wanted to. I want to kill a previous "ruby tweetsearcher.rb -start", already running in background.
How do I proceed?
Typically, the PID is stored in a file that is then read to stop it.
Calling Process.kill(9,Process.pid) kills the "stopper" process itself, rather than the one it's trying to stop.
Here's a guide to writing daemons in Ruby: http://codeincomplete.com/posts/2014/9/15/ruby_daemons/
As you can see, it's not a trivial process.
Here is another blog that suggests that you should not try to daemonize at all, but instead rely on a process monitoring system to take care of those concerns: https://www.mikeperham.com/2014/09/22/dont-daemonize-your-daemons/

Can a standalone ruby script (windows and mac) reload and restart itself?

I have a master-workers architecture where the number of workers is growing on a weekly basis. I can no longer be expected to ssh or remote console into each machine to kill the worker, do a source control sync, and restart. I would like to be able to have the master place a message out on the network that tells each machine to sync and restart.
That's where I hit a roadblock. If I were using any sane platform, I could just do:
exec('ruby', __FILE__)
...and be done. However, I did the following test:
p Process.pid
sleep 1
exec('ruby', __FILE__)
...and on Windows, I get one ruby instance for each call to exec. None of them die until I hit ^C on the window in question. On every platform I tried this on, it is executing the new version of the file each time, which I have verified this by making simple edits to the test script while the test marched along.
The reason I'm printing the pid is to double-check the behavior I'm seeing. On windows, I am getting a different pid with each execution - which I would expect, considering that I am seeing a new process in the task manager for each run. The mac is behaving correctly: the pid is the same for every system call and I have verified with dtrace that each run is trigging a call to the execve syscall.
So, in short, is there a way to get a windows ruby script to restart its execution so it will be running any code - including itself - that has changed during its execution? Please note that this is not a rails application, though it does use activerecord.
After trying a number of solutions (including the one submitted by Byron Whitlock, which ultimately put me onto the path to a satisfactory end) I settled upon:
IO.popen("start cmd /C ruby.exe #{$0} #{ARGV.join(' ')}")
sleep 5
I found that if I didn't sleep at all after the popen, and just exited, the spawn would frequently (>50% of the time) fail. This is not cross-platform obviously, so in order to have the same behavior on the mac:
IO.popen("xterm -e \"ruby blah blah blah\"&")
The classic way to restart a program is to write another one that does it for you. so you spawn a process to restart.exe <args>, then die or exit; restart.exe waits until the calling script is no longer running, then starts the script again.

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.

Resources