Skip to content

Commit

Permalink
Added a soft stop and switched old one to kill.
Browse files Browse the repository at this point in the history
  • Loading branch information
DAddYE committed Aug 26, 2011
1 parent 057bb48 commit 3159efa
Show file tree
Hide file tree
Showing 10 changed files with 129 additions and 41 deletions.
4 changes: 0 additions & 4 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,3 @@ source "http://rubygems.org"

# Specify your gem's dependencies in forever.gemspec
gemspec

gem 'guard'
gem 'guard-rspec'
gem 'growl'
5 changes: 0 additions & 5 deletions Guardfile

This file was deleted.

4 changes: 2 additions & 2 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ end

desc "Bump version on github"
task :bump do
puts "\e[31mNothing to commit (working directory clean)\e[0m" and return unless `git status -s`.chomp!
puts "\e[31mNothing to commit (working directory clean)\e[0m" and return unless `git status -s`.strip == ""
version = Bundler.load_gemspec(Dir[File.expand_path('../*.gemspec', __FILE__)].first).version
sh "git add .; git commit -a -m \"Bump to version #{version}\""
end
Expand All @@ -24,4 +24,4 @@ RSpec::Core::RakeTask.new("spec") do |t|
t.rspec_opts = %w(-fs --color --fail-fast)
end

task :default => :spec
task :default => :spec
19 changes: 18 additions & 1 deletion bin/foreverb
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,23 @@ class CLI < Thor
end
end

desc "kill [DAEMON] [--all] [--yes]", "Kill one or more matching daemons"
method_option :all, :type => :boolean, :aliases => "-a", :desc => "All matching daemons"
method_option :yes, :type => :boolean, :aliases => "-y", :desc => "Don't ask permission to kill daemon"
def kill(daemon=nil)
find(daemon, :multiple => options.all).each do |conf|
if options.yes || yes?("Do you want really kill \e[1m#{conf[:file]}\e[0m?")
say_status "KILLING", conf[:file]
begin
pid = File.read(conf[:pid]).to_i
Process.kill(:INT, pid)
rescue Exception => e
say_status "ERROR", e.message, :red
end
end
end
end

desc "start [DAEMON] [--all] [--yes]", "Start one or more matching daemons"
method_option :all, :type => :boolean, :aliases => "-a", :desc => "All matching daemons"
method_option :yes, :type => :boolean, :aliases => "-y", :desc => "Don't ask permission to start the daemon"
Expand Down Expand Up @@ -122,4 +139,4 @@ class CLI < Thor
end

ARGV << "-h" if ARGV.empty?
CLI.start(ARGV)
CLI.start(ARGV)
6 changes: 5 additions & 1 deletion examples/sample
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ require 'forever'
Forever.run do
dir File.expand_path('../', __FILE__) # Default is ../../__FILE__

every 5.seconds do
puts 'every 5 seconds'
end

on_ready do
puts "All jobs will will wait me for 1 second"; sleep 1
end
Expand Down Expand Up @@ -50,4 +54,4 @@ Forever.run do
on_exit do
puts "Bye bye"
end
end
end
112 changes: 89 additions & 23 deletions lib/forever/base.rb
Original file line number Diff line number Diff line change
Expand Up @@ -16,20 +16,37 @@ def initialize(options={}, &block)

write_config!

if ARGV.any? { |arg| arg == "config" }
print config.to_yaml
return
case ARGV[0]
when 'config'
print config.to_yaml
exit
when 'start', 'restart', 'up', nil
stop
when 'stop'
stop
exit
when 'kill'
stop!
exit
when 'help', '-h'
print <<-RUBY.gsub(/ {10}/,'') % File.basename(file)
Usage: \e[1m./%s\e[0m [start|stop|kill|restart|config]
Commands:
start stop (if present) the daemon and perform a start
stop stop the daemon if a during when it is idle
restart same as start
kill force stop by sending a KILL signal to the process
config show the current daemons config
RUBY
exit
end

return if ARGV.any? { |arg| arg == "up" }

stop!

return if ARGV.any? { |arg| arg == "stop" }

fork do
$0 = "Forever: #{$0}"
print "=> Process demonized with pid #{Process.pid} with Forever v.#{Forever::VERSION}\n"
print "=> Process demonized with pid \e[1m#{Process.pid}\e[0m with Forever v.#{Forever::VERSION}\n"

%w(INT TERM KILL).each { |signal| trap(signal) { stop! } }
trap(:HUP) do
Expand All @@ -46,12 +63,25 @@ def initialize(options={}, &block)

threads = []
safe_call(on_ready) if on_ready
started_at = Time.now

jobs.each do |job|
threads << Thread.new do
loop { job.time?(Time.now) ? safe_call(job) : sleep(1) }
loop do
break if File.exist?(stop_txt) && File.mtime(stop_txt) > started_at
job.time?(Time.now) ? safe_call(job) : sleep(1)
end
end
end

# Launch our workers
threads.map(&:join)

# If we are here it means we are exiting so we can remove the pid and pending stop.txt
FileUtils.rm_f(pid)
FileUtils.rm_f(stop_txt)

on_exit.call if on_exit
end

self
Expand Down Expand Up @@ -95,19 +125,30 @@ def pid(value=nil)
# Search if there is a running process and stop it
#
def stop!
if exists?(pid)
_pid = File.read(pid).to_i
print "=> Found pid #{_pid}...\n"
FileUtils.rm_f(stop_txt)
if running?
pid_was = File.read(pid).to_i
FileUtils.rm_f(pid)
begin
print "=> Killing process #{_pid}...\n"
on_exit.call if on_exit
Process.kill(:KILL, _pid)
rescue Errno::ESRCH => e
puts "=> #{e.message}"
end
print "=> Killing process \e[1m%d\e[0m...\n" % pid_was
on_exit.call if on_exit
Process.kill(:KILL, pid_was)
else
print "=> Pid not found, process seems don't exist!\n"
print "=> Process with \e[1mnot found\e[0m"
end
end

##
# Perform a soft stop
#
def stop
if running?
print '=> Waiting the daemon\'s death '
FileUtils.touch(stop_txt)
while running?(true)
print '.'; $stdout.flush
sleep 1
end
print " \e[1mDONE\e[0m\n"
end
end

Expand All @@ -132,6 +173,27 @@ def on_ready(&block)
block_given? ? @_on_ready = block : @_on_ready
end

##
# Returns true if the pid exist and the process is running
#
def running?(silent=false)
if exists?(pid)
current = File.read(pid).to_i
print "=> Found pid \e[1m%d\e[0m...\n" % current unless silent
else
print "=> Pid \e[1mnot found\e[0m, process seems don't exist!\n" unless silent
return false
end

is_running = begin
Process.kill(0, current)
rescue Errno::ESRCH
false
end

is_running
end

def to_s
"#<Forever dir:#{dir}, file:#{file}, log:#{log}, pid:#{pid} jobs:#{jobs.size}>"
end
Expand Down Expand Up @@ -161,5 +223,9 @@ def safe_call(block)
on_error[e] if on_error
end
end

def stop_txt
@_stop_txt ||= File.join(dir, 'stop.txt')
end
end # Base
end # Forever
end # Forever
2 changes: 1 addition & 1 deletion lib/forever/version.rb
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
module Forever
VERSION = "0.2.4" unless defined?(Forever::VERSION)
VERSION = "0.2.5" unless defined?(Forever::VERSION)
end
11 changes: 10 additions & 1 deletion spec/cli_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -22,4 +22,13 @@
result.should_not match(/ERROR/)
cli('list').should match(/NOT RUNNING/)
end
end

it "should kill daemons" do
run_example
cli('list').should match(/RUNNING/)
result = cli('kill -a -y')
result.should match(/KILLING/)
result.should_not match(/ERROR/)
cli('list').should match(/NOT RUNNING/)
end
end
5 changes: 3 additions & 2 deletions spec/foreverb_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
describe Forever do

before :each do
$stdout = StringIO.new
ARGV << 'up'
end

Expand Down Expand Up @@ -41,7 +42,7 @@
sleep 0.1 while !File.exist?(@forever.pid)
pid = File.read(@forever.pid).to_i
Process.waitpid(pid)
$stdout.string.should match(/pid not found/i)
$stdout.string.should match(/not found/i)
$stdout = stdout_was
end
end
end
2 changes: 1 addition & 1 deletion spec/spec_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,4 @@ def cli(task)
end
ARGV.clear
end
end
end

0 comments on commit 3159efa

Please sign in to comment.