Thin doesn't respond to SIGINT or SIGTERM - ruby

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.

Related

Asynchronously running a ruby script from ruby

Based on an external redis queue, I want a Sinatra application to run a script like this:
ruby fetch_vin.rb vin_number_123
This will fire up watir-webdriver and report to the queue appropriately. When the script is finished, everything but the Sinatra app should close.
It seems however that Thread, as well as exec and spawn are all blocking when ran from inside ruby.
How do I fire & forget?
You can use Process#spawn:
pid = Process.spawn("ruby fetch_vin.rb vin_number_123")
Process.detach(pid)
I think the bit you were missing was calling detach after the process was spawned. This will detach and let both processes continue to run. Will work for any command, not just a ruby script.
See Process Ruby Docs for more details.

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/

run_later with rackup fails to exit with ctrl-c - 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.

How can I create a daemon with Thor (ruby)?

I would like to use the popular Thor gem to create a daemonized task. My Thor class looks like this:
require 'rubygems'
require 'daemons'
require 'thor'
class CLI < Thor
desc "start", "Startup the App"
method_option :daemonize, :aliases => "-d", :default => false, :type => :boolean, :banner => "Run as daemon"
def start
run_app(options[:daemonize])
end
desc "stop", "Stop the daemon"
def stop
stop_app
end
no_tasks {
def run_app(run_as_daemon)
# Run the application code
Daemons.daemonize if run_as_daemon
# loop until stopped or interrupted
# ...
end
def stop_app
#stop the app
end
}
end
So here I've setup a basic thor class with two tasks, start and stop. I'm also, currently using the Daemons gem, but that isn't required. The part that I'm struggling with is that when this app runs as "run_thor_app.rb start" everything runs just fine. Obviously the stop task isn't needed in this instance. But when I run "run_thor_app.rb start -d" the app runs until Daemons.daemonize runs and then it quits. Checking the running processes shows that nothing is running in the background.
Even if something were running, I wouldn't know how to approach the stop task. For example, how do you detect that the app is running as a daemon and stop it. I've looked at Daemons::Monitor, but the documentation isn't clear on how that works and when I tried it, it didn't work.
It seems to me that this would be a good use case for something that is built into Thor, but searching through the code on github hasn't revealed anything to me. Maybe I just missed it somewhere. In any case, I think it would be good to document a best practice or a pattern for handling daemons with Thor for others to reference.
The way you usually manage daemon processes is by having them write their PID in a file. This makes it possible for another process to discover the daemon's PID, and kill it (or send some other signal).
Your code should work. I tried a bare bones script that used the deamons gem, and it took me a few tries until I found the deamonized process. I figured it would get the same name as the parent process, or something similar, but instead it's name was "self". Remember that the daemonized process will no longer write to STDOUT.
Anyway, try this:
# set up everything
# then daemonize
Daemons.daemonize
# and write a pid file
File.open('/tmp/mydaemon.pid', 'w') { |f| f.puts(Process.pid) }
loop do
# do something
# this loop is important, if the script ends the daemon dies
end
and check the /tmp/mydaemon.pid file for the PID. Then run ps ax | grep x where x is the PID. Run cat /tmp/mydaemon.pid | xargs kill` to kill the daemon.
I think the daemons' gem has some helpers for managing PidFiles, check out PidFile in http://rubydoc.info/gems/daemons/1.1.0/frames

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