views:

198

answers:

2

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.

A: 

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.

Byron Whitlock
I was hoping to avoid that situation if at all possible. The script in question already IS a restarter for scripts that do the real work. This was necessary to get around the threading limitations of ruby on windows in the face of scripts that call out to other applications (like visual studio.) If I can avoid having a starter call a starter that calls a worker, I'd be much happier. Besides - that wouldn't entirely fix the problem: what happens if I change the code for the top-level starter? I've only moved the problem up one layer without actually solving it.
A: 

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\"&")