Compare commits
17 commits
Author | SHA1 | Date | |
---|---|---|---|
|
92060db994 | ||
|
0e90737ae1 | ||
|
f09d6150dd | ||
|
c34cc60ae6 | ||
|
5b7d63fb2d | ||
|
37ac8bb3db | ||
|
960f3ef7a9 | ||
|
d7edbb750e | ||
|
f11b7df104 | ||
|
9551fbe35d | ||
|
fc48ded7ba | ||
|
56070055d8 | ||
|
5ef72caa6b | ||
|
5169bee0ea | ||
|
e11976f9a2 | ||
|
899a1dd399 | ||
|
c992701299 |
2
.gitignore
vendored
Normal file
2
.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
||||||
|
.*.swp
|
||||||
|
pkg
|
12
Gemfile
Normal file
12
Gemfile
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
source "http://rubygems.org"
|
||||||
|
|
||||||
|
# Add dependencies to develop your gem here.
|
||||||
|
# Include everything needed to run rake, tests, features, etc.
|
||||||
|
group :development do
|
||||||
|
gem "shoulda"
|
||||||
|
gem "yard"
|
||||||
|
gem "rdoc"
|
||||||
|
gem "bundler"
|
||||||
|
gem "jeweler"
|
||||||
|
gem "simplecov"
|
||||||
|
end
|
46
Gemfile.lock
Normal file
46
Gemfile.lock
Normal file
|
@ -0,0 +1,46 @@
|
||||||
|
GEM
|
||||||
|
remote: http://rubygems.org/
|
||||||
|
specs:
|
||||||
|
activesupport (3.2.13)
|
||||||
|
i18n (= 0.6.1)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
bourne (1.4.0)
|
||||||
|
mocha (~> 0.13.2)
|
||||||
|
git (1.2.5)
|
||||||
|
i18n (0.6.1)
|
||||||
|
jeweler (1.8.4)
|
||||||
|
bundler (~> 1.0)
|
||||||
|
git (>= 1.2.5)
|
||||||
|
rake
|
||||||
|
rdoc
|
||||||
|
json (1.7.7)
|
||||||
|
metaclass (0.0.1)
|
||||||
|
mocha (0.13.3)
|
||||||
|
metaclass (~> 0.0.1)
|
||||||
|
multi_json (1.7.2)
|
||||||
|
rake (10.0.4)
|
||||||
|
rdoc (4.0.1)
|
||||||
|
json (~> 1.4)
|
||||||
|
shoulda (3.4.0)
|
||||||
|
shoulda-context (~> 1.0, >= 1.0.1)
|
||||||
|
shoulda-matchers (~> 1.0, >= 1.4.1)
|
||||||
|
shoulda-context (1.1.0)
|
||||||
|
shoulda-matchers (1.5.6)
|
||||||
|
activesupport (>= 3.0.0)
|
||||||
|
bourne (~> 1.3)
|
||||||
|
simplecov (0.7.1)
|
||||||
|
multi_json (~> 1.0)
|
||||||
|
simplecov-html (~> 0.7.1)
|
||||||
|
simplecov-html (0.7.1)
|
||||||
|
yard (0.8.5.2)
|
||||||
|
|
||||||
|
PLATFORMS
|
||||||
|
ruby
|
||||||
|
|
||||||
|
DEPENDENCIES
|
||||||
|
bundler
|
||||||
|
jeweler
|
||||||
|
rdoc
|
||||||
|
shoulda
|
||||||
|
simplecov
|
||||||
|
yard
|
78
Rakefile
78
Rakefile
|
@ -1,57 +1,49 @@
|
||||||
|
# encoding: utf-8
|
||||||
|
|
||||||
require 'rubygems'
|
require 'rubygems'
|
||||||
|
require 'bundler'
|
||||||
|
begin
|
||||||
|
Bundler.setup(:default, :development)
|
||||||
|
rescue Bundler::BundlerError => e
|
||||||
|
$stderr.puts e.message
|
||||||
|
$stderr.puts "Run `bundle install` to install missing gems"
|
||||||
|
exit e.status_code
|
||||||
|
end
|
||||||
require 'rake'
|
require 'rake'
|
||||||
|
|
||||||
begin
|
require 'jeweler'
|
||||||
require 'jeweler'
|
Jeweler::Tasks.new do |gem|
|
||||||
Jeweler::Tasks.new do |gem|
|
# gem is a Gem::Specification... see http://docs.rubygems.org/read/chapter/20 for more options
|
||||||
gem.name = "robustserver"
|
gem.name = "robustserver"
|
||||||
gem.summary = %Q{Robust Server}
|
gem.summary = %Q{Robust Server}
|
||||||
gem.description = %Q{Protects your Server against SIGS and unplaned exceptions}
|
gem.description = %Q{Protects your Server against SIGS and rescues all exceptions.}
|
||||||
gem.email = "Denis.Knauf@gmail.com"
|
gem.email = "Denis.Knauf@gmail.com"
|
||||||
gem.homepage = "http://github.com/DenisKnauf/robustserver"
|
gem.homepage = "http://github.com/DenisKnauf/robustserver"
|
||||||
gem.authors = ["Denis Knauf"]
|
gem.authors = ["Denis Knauf"]
|
||||||
gem.files = ["AUTHORS", "README.md", "VERSION", "lib/**/*.rb", "test/**/*.rb"]
|
gem.files = %w[AUTHORS README.md VERSION lib/**/*.rb test/**/*.rb]
|
||||||
gem.require_paths = ["lib"]
|
gem.require_paths = %w[lib]
|
||||||
end
|
# dependencies defined in Gemfile
|
||||||
Jeweler::GemcutterTasks.new
|
|
||||||
rescue LoadError
|
|
||||||
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
|
||||||
end
|
end
|
||||||
|
Jeweler::RubygemsDotOrgTasks.new
|
||||||
|
|
||||||
require 'rake/testtask'
|
require 'rake/testtask'
|
||||||
Rake::TestTask.new(:test) do |test|
|
Rake::TestTask.new(:test) do |test|
|
||||||
test.libs << 'lib' << 'test' << 'ext'
|
test.libs << 'lib' << 'test'
|
||||||
test.pattern = 'test/**/*_test.rb'
|
test.pattern = 'test/**/test_*.rb'
|
||||||
test.verbose = true
|
test.verbose = true
|
||||||
end
|
end
|
||||||
|
|
||||||
begin
|
=begin
|
||||||
require 'rcov/rcovtask'
|
require 'rcov/rcovtask'
|
||||||
Rcov::RcovTask.new do |test|
|
Rcov::RcovTask.new do |test|
|
||||||
test.libs << 'test'
|
test.libs << 'test'
|
||||||
test.pattern = 'test/**/*_test.rb'
|
test.pattern = 'test/**/test_*.rb'
|
||||||
test.verbose = true
|
test.verbose = true
|
||||||
end
|
test.rcov_opts << '--exclude "gems/*"'
|
||||||
rescue LoadError
|
|
||||||
task :rcov do
|
|
||||||
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
=end
|
||||||
task :test => :check_dependencies
|
|
||||||
|
|
||||||
task :default => :test
|
task :default => :test
|
||||||
|
|
||||||
require 'rake/rdoctask'
|
require 'yard'
|
||||||
Rake::RDocTask.new do |rdoc|
|
YARD::Rake::YardocTask.new
|
||||||
if File.exist?('VERSION')
|
|
||||||
version = File.read('VERSION')
|
|
||||||
else
|
|
||||||
version = ""
|
|
||||||
end
|
|
||||||
|
|
||||||
rdoc.rdoc_dir = 'rdoc'
|
|
||||||
rdoc.title = "sbdb #{version}"
|
|
||||||
rdoc.rdoc_files.include('README*')
|
|
||||||
rdoc.rdoc_files.include('lib/**/*.rb')
|
|
||||||
end
|
|
||||||
|
|
|
@ -4,6 +4,7 @@ def Signal.signame s
|
||||||
when String then s
|
when String then s
|
||||||
when Symbol then s.to_s
|
when Symbol then s.to_s
|
||||||
when Fixnum then list.invert[s]
|
when Fixnum then list.invert[s]
|
||||||
|
else raise ArgumentError, "String, Symbol or Fixnum expected, not #{s.class}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -12,6 +13,7 @@ def Signal.sig s
|
||||||
when Fixnum then s
|
when Fixnum then s
|
||||||
when String then list[s]
|
when String then list[s]
|
||||||
when Symbol then list[s.to_s]
|
when Symbol then list[s.to_s]
|
||||||
|
else raise ArgumentError, "String, Symbol or Fixnum expected, not #{s.class}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -25,25 +27,65 @@ def Signal.[] s
|
||||||
when String then list[s]
|
when String then list[s]
|
||||||
when Symbol then list[s.to_s]
|
when Symbol then list[s.to_s]
|
||||||
when Fixnum then list.invert[s]
|
when Fixnum then list.invert[s]
|
||||||
else raise ArgumentError
|
else raise ArgumentError, "String, Symbol or Fixnum expected, not #{s.class}"
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Description
|
||||||
|
# ===========
|
||||||
|
#
|
||||||
|
# Counts retries ot something. If the retries are to often in a short time,
|
||||||
|
# you shouldn't retry again.
|
||||||
|
#
|
||||||
|
# Examples
|
||||||
|
# ========
|
||||||
|
#
|
||||||
|
# Strings aren't Integers and 2*"Text" will raise TypeError.
|
||||||
|
#
|
||||||
|
# retries = Retry.new 5, 1
|
||||||
|
# begin
|
||||||
|
# array_of_ints_and_some_strings.each do |i|
|
||||||
|
# puts 2*i
|
||||||
|
# end
|
||||||
|
# rescue TypeError
|
||||||
|
# retries.retry? and retry
|
||||||
|
# raise $!
|
||||||
|
# end
|
||||||
|
#
|
||||||
|
# Retry.new( 10, 30).run( ConnectionLost) do
|
||||||
|
# try_to_connect_to_db
|
||||||
|
# try_query
|
||||||
|
# end
|
||||||
class Retries
|
class Retries
|
||||||
attr_accessor :max, :range
|
attr_accessor :max, :range
|
||||||
attr_reader :count, :last
|
attr_reader :count, :last
|
||||||
|
|
||||||
|
# max: How many retries in range-time are allowed maximal.
|
||||||
|
# range: In which time-range are these retries are allowed
|
||||||
def initialize max = nil, range = nil
|
def initialize max = nil, range = nil
|
||||||
@max, @range, @count, @last = max || 10, range || 10, 0, Time.now
|
@max, @range, @count, @last = max || 10, range || 10, 0, Time.now
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Counts retries on every call.
|
||||||
|
# If these retries are to often - max times in range - it will return false
|
||||||
|
# else true.
|
||||||
|
# Now you can say: "I give up, to many retries, it seems it doesn't work."
|
||||||
def retry?
|
def retry?
|
||||||
@count = @last + @range > Time.now ? @count + 1 : 1
|
@count = @last + @range > Time.now ? @count + 1 : 1
|
||||||
@last = Time.now
|
@last = Time.now
|
||||||
@count < @max
|
@count < @max
|
||||||
end
|
end
|
||||||
|
|
||||||
def run ex, &e
|
# Automatical retrieing on raised exceptions in block.
|
||||||
|
# ex: Your expected Esception you will rescue. Default: Object, so realy everything.
|
||||||
|
#
|
||||||
|
# Example:
|
||||||
|
# Retries.new( 10, 30).run ArgumentError do something_do_which_could_raise_exception ArgumentError end
|
||||||
|
#
|
||||||
|
# This will retry maximal 10 times in 30 seconds to Call this block. But only rescues ArgumentError!
|
||||||
|
# Every other Error it will ignore and throws Exception. No retry.
|
||||||
|
def run ex = nil, &e
|
||||||
|
ex ||= Object
|
||||||
begin e.call *args
|
begin e.call *args
|
||||||
rescue ex
|
rescue ex
|
||||||
retries.retry? and retry
|
retries.retry? and retry
|
||||||
|
@ -51,20 +93,33 @@ class Retries
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Easy problem-handler for your Server.
|
||||||
|
#
|
||||||
|
# Problem: Your process should not crash, it should be available for anytime.
|
||||||
|
# If an exception will be raised, you have to handle it, or it will be shutdown abnormaly.
|
||||||
|
# Or if a signal tries to "kill" your program, your program will shutdown abnormaly, too.
|
||||||
|
#
|
||||||
|
# RobustServer handles any exception / kill, logs it and prevents the server to shutting down.
|
||||||
|
#
|
||||||
|
# For implementation a server, create a subclass of RobustServer and implement the *#run*-method.
|
||||||
|
# Anytime this *#run*-method returns or an exception will be raised, it will be rescued and run recalled.
|
||||||
|
# For initialization, you can override **#initialize**, but don't forget to call **super**.
|
||||||
class RobustServer
|
class RobustServer
|
||||||
attr_reader :signals
|
class UnimplementedRun <Exception
|
||||||
|
end
|
||||||
|
attr_reader :signals, :output
|
||||||
|
|
||||||
def self.main *argv
|
def self.main *argv
|
||||||
self.new( *argv).main
|
self.new( *argv).main
|
||||||
end
|
end
|
||||||
|
|
||||||
def initialize *p
|
def initialize *_
|
||||||
sh = method :signal_handler
|
sh = method :signal_handler
|
||||||
@sigs = {
|
@sigs = {
|
||||||
Signal[:INT] => sh, Signal[:HUP] => nil, Signal[:TERM] => sh,
|
Signal[:INT] => sh, Signal[:HUP] => nil, Signal[:TERM] => sh,
|
||||||
Signal[:KILL] => sh, Signal[:USR1] => nil, Signal[:USR2] => nil
|
Signal[:KILL] => sh, Signal[:USR1] => nil, Signal[:USR2] => nil
|
||||||
}
|
}
|
||||||
@signals = []
|
@signals, @output = [], $stderr
|
||||||
end
|
end
|
||||||
|
|
||||||
def trapping
|
def trapping
|
||||||
|
@ -72,26 +127,42 @@ class RobustServer
|
||||||
end
|
end
|
||||||
|
|
||||||
def signal_handler s
|
def signal_handler s
|
||||||
$stderr.puts [:signal, s, Signal[s]].inspect
|
output.puts [:signal, s, Signal[s]].inspect
|
||||||
s = s
|
|
||||||
@signals.push s unless @signals.include? s
|
@signals.push s unless @signals.include? s
|
||||||
end
|
end
|
||||||
|
|
||||||
def main max = nil, range = nil
|
def main max = nil, range = nil
|
||||||
retries = Retries.new max, range
|
retries = Retries.new max, range
|
||||||
trapping
|
trapping
|
||||||
$stderr.puts "Arbeit wird nun aufgenommen..."
|
output.puts "Running...."
|
||||||
begin
|
begin
|
||||||
self.run
|
self.run
|
||||||
rescue SystemExit, Interrupt, SignalException
|
rescue UnimplementedRun
|
||||||
$stderr.puts "Das Beenden des Programms wurde angefordert. #{$!}"
|
output.puts $!.message
|
||||||
|
exit 1
|
||||||
|
rescue SystemExit
|
||||||
|
output.puts "Server interrupted by signal: #$!"
|
||||||
|
raise
|
||||||
|
rescue Interrupt, SignalException
|
||||||
|
output.puts "Server interrupted by signal: #$!"
|
||||||
|
exit 0
|
||||||
rescue Object
|
rescue Object
|
||||||
$stderr.puts [:rescue, $!, $!.class, $!.backtrace].inspect
|
output.puts [:rescue, $!, $!.class, $!.backtrace].inspect
|
||||||
retry if retries.retry?
|
retry if retries.retry?
|
||||||
$stderr.print "Zuviele Fehler in zu kurzer Zeit. Ich gebe auf und "
|
output.print "Too many errors in too short time. Give up: "
|
||||||
|
exit 2
|
||||||
end
|
end
|
||||||
$stderr.puts "Unbeachtete Signale: #{@signals.map(&Signal.method(:[])).join( ', ')}"
|
ensure
|
||||||
|
output.puts "Disregarded signals: #{@signals.map(&Signal.method(:[])).join( ', ')}" unless @signals.empty?
|
||||||
trapping
|
trapping
|
||||||
$stderr.puts "Beende mich selbst."
|
self.at_exit
|
||||||
|
output.puts "Shutdown."
|
||||||
|
end
|
||||||
|
|
||||||
|
def run
|
||||||
|
raise UnimplementedRun, "Unimplemented #{self.class.name}#run."
|
||||||
|
end
|
||||||
|
|
||||||
|
def at_exit
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,40 +1,57 @@
|
||||||
# Generated by jeweler
|
# Generated by jeweler
|
||||||
# DO NOT EDIT THIS FILE DIRECTLY
|
# DO NOT EDIT THIS FILE DIRECTLY
|
||||||
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
||||||
# -*- encoding: utf-8 -*-
|
# -*- encoding: utf-8 -*-
|
||||||
|
|
||||||
Gem::Specification.new do |s|
|
Gem::Specification.new do |s|
|
||||||
s.name = %q{robustserver}
|
s.name = "robustserver"
|
||||||
s.version = "0.0.0.1"
|
s.version = "0.0.3"
|
||||||
|
|
||||||
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
||||||
s.authors = ["Denis Knauf"]
|
s.authors = ["Denis Knauf"]
|
||||||
s.date = %q{2010-03-07}
|
s.date = "2013-04-15"
|
||||||
s.description = %q{Protects your Server against SIGS and unplaned exceptions}
|
s.description = "Protects your Server against SIGS and rescues all exceptions."
|
||||||
s.email = %q{Denis.Knauf@gmail.com}
|
s.email = "Denis.Knauf@gmail.com"
|
||||||
s.extra_rdoc_files = [
|
s.extra_rdoc_files = [
|
||||||
"LICENSE",
|
"LICENSE",
|
||||||
"README.md"
|
"README.md"
|
||||||
]
|
]
|
||||||
s.files = [
|
s.files = [
|
||||||
|
"AUTHORS",
|
||||||
"README.md",
|
"README.md",
|
||||||
"VERSION",
|
"VERSION",
|
||||||
"lib/robustserver.rb"
|
"lib/robustserver.rb"
|
||||||
]
|
]
|
||||||
s.homepage = %q{http://github.com/DenisKnauf/robustserver}
|
s.homepage = "http://github.com/DenisKnauf/robustserver"
|
||||||
s.rdoc_options = ["--charset=UTF-8"]
|
|
||||||
s.require_paths = ["lib"]
|
s.require_paths = ["lib"]
|
||||||
s.rubygems_version = %q{1.3.5}
|
s.rubygems_version = "1.8.23"
|
||||||
s.summary = %q{Robust Server}
|
s.summary = "Robust Server"
|
||||||
|
|
||||||
if s.respond_to? :specification_version then
|
if s.respond_to? :specification_version then
|
||||||
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
|
||||||
s.specification_version = 3
|
s.specification_version = 3
|
||||||
|
|
||||||
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
||||||
|
s.add_development_dependency(%q<shoulda>, [">= 0"])
|
||||||
|
s.add_development_dependency(%q<yard>, [">= 0"])
|
||||||
|
s.add_development_dependency(%q<rdoc>, [">= 0"])
|
||||||
|
s.add_development_dependency(%q<bundler>, [">= 0"])
|
||||||
|
s.add_development_dependency(%q<jeweler>, [">= 0"])
|
||||||
|
s.add_development_dependency(%q<simplecov>, [">= 0"])
|
||||||
else
|
else
|
||||||
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
||||||
|
s.add_dependency(%q<yard>, [">= 0"])
|
||||||
|
s.add_dependency(%q<rdoc>, [">= 0"])
|
||||||
|
s.add_dependency(%q<bundler>, [">= 0"])
|
||||||
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
||||||
|
s.add_dependency(%q<simplecov>, [">= 0"])
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
|
s.add_dependency(%q<shoulda>, [">= 0"])
|
||||||
|
s.add_dependency(%q<yard>, [">= 0"])
|
||||||
|
s.add_dependency(%q<rdoc>, [">= 0"])
|
||||||
|
s.add_dependency(%q<bundler>, [">= 0"])
|
||||||
|
s.add_dependency(%q<jeweler>, [">= 0"])
|
||||||
|
s.add_dependency(%q<simplecov>, [">= 0"])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue