run_later with rackup fails to exit with ctrl-c - Ruby - ruby

I'm running a Sinatra application with rackup using this run_later https://github.com/elecklider/sinatra_run_later module (my own fork of https://github.com/pmamediagroup/sinatra_run_later). I can't, however, seem to get it to exit cleanly when I send ctrl-c to rackup. It kicks back with the error ERROR SystemExit: exit on line 38. How can I get it to exit nicely when I close the rackup process?
EDIT:
I've been screwing around with this and the error is raised here:
trap :INT do
RunLater::Worker.shutdown
exit # here.
end
And it seems that commenting out the whole trap block gets it to clean up nicely. In essence, this answers the question of how to get it to clean up nicely but I have no idea why so if anyone can offer some clarification I'd really appreciate it.

Related

Setting Connection to "close" in Sinatra

I have this simple sinatra web app:
require 'sinatra'
get '/' do
"Success."
end
get '/app' do
"done"
response["Connection"] = "Close"
`sudo pkill blink`
`gpio write 0 0`
`sudo ./blink #{params["func"]}`
end
./blink is a program that runs forever and does not terminate, so when I access http://127.0.0.1/app?func=2 in a browser, I just get a loading loop and "done" is not shown as the result, however the program I am trying to run in the /app block is running.
I thought maybe setting the Connection header to Close would solve the problem, but using the code above, which I thought would set the header, still has the Connection header to Keep-Alive
Any help? Thanks!
Referencing this SO question Spawn a background process in Ruby and with some help from #andrykonchin, I was able to resolve my issue using this:
pid = fork do
`sudo ./blink #{params["func"]}`
end
Process.detach(pid)

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/

Ruby Signal.trap exit(-1)

I am trying to unit test a command line tool, that uses trollop. One of the calls it makes to trollop is Trollop::die "my message", which underneath calls exit(-1)
Now, this makes my unit tests to fail, because this kills rake - I've tried using Signal.trap to trap the signal, but it doesn't seem to have any effect. Does anyone have any idea on how to trap this kind of exit code ?

Thin doesn't respond to SIGINT or SIGTERM

bundle exec thin start -p 3111 gives the following output:
Using rack adapter
Thin web server (v1.2.11 codename Bat-Shit Crazy)
Maximum connections set to 1024
Listening on 0.0.0.0:3111, CTRL+C to stop
^C
Ctrl-C doesn't do anything (SIGINT). Neither does kill (SIGTERM).
I've found a few references to this behavior, but no solutions. The problem seems to be either in eventmachine (bundled with latest thin), in ruby 1.9.2-r290, or in the linux kernel (Ubuntu 10.4 LTS, 2.6.38.3-linode32).
It happens with my project, but not with a brand new rails project.
References:
http://groups.google.com/group/thin-ruby/browse_thread/thread/4b7c28e8964b5001?fwc=2
My guess is that either something's tying up the EventMachine reactor loop preventing it from exiting, or something's trapping SIGINT.
As a simple example of the former, put this into config.ru and run with thin -p 4567 start:
require 'thin'
require 'sinatra'
require 'eventmachine'
get '/' do
"hello world"
end
run Sinatra::Application
EventMachine.schedule do
trap("INT") do
puts "Caught SIGINT"
EventMachine.stop # this is useless
# exit # this stops the EventMachine
end
i = 0
while i < 10
puts "EM Running"
i += 1
sleep 1
end
end
Without trapping the SIGINT, you get the same behavior as when trapping it and calling EM.stop. EM.stop (at least in the pure ruby version, which you can run with EVENTMACHINE_LIBRARY="pure_ruby" thin start) sets a flag that a stop has been requested, which is picked up inside the reactor loop. If the reactor loop is stuck on a step (as in the above case), then it won't exit.
So a couple options:
use the workaround above of trapping SIGINT and forcing an exit. This could leave connections in an unclean state, but they don't call it quick & dirty for nothing ;)
you could put the blocking code inside a Thread or a Fiber, which will allow the reactor to keep running.
look for long-running tasks or loops inside your code, and convert these to be EventMachine aware. em-http-request is a great library for external http requests, and em-synchrony has several other protocols (for database connections, tcp connection pools, etc.). In the above example, this is straightforward: EventMachine.add_periodic_timer(1) { puts "EM Running" }
In your actual code, this might be harder to track down, but look for any places where you spawn threads and join them, or large loops. A profiling tool can help show what code is running when you try to exit, and lastly you can try disabling various parts of the system and libraries to figure out where the culprit is.

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.

Resources