kennethkalmer-daemon-kit 0.1.5.1 → 0.1.6
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +9 -0
- data/Manifest.txt +7 -1
- data/TODO.txt +2 -1
- data/app_generators/daemon_kit/daemon_kit_generator.rb +7 -3
- data/app_generators/daemon_kit/templates/config/environment.rb +4 -0
- data/app_generators/daemon_kit/templates/config/post-daemonize/readme +5 -0
- data/app_generators/daemon_kit/templates/config/{initializers → pre-daemonize}/readme +2 -1
- data/app_generators/daemon_kit/templates/lib/daemon.rb +2 -1
- data/daemon_generators/amqp/amqp_generator.rb +2 -2
- data/daemon_generators/cron/cron_generator.rb +2 -2
- data/daemon_generators/jabber/jabber_generator.rb +2 -2
- data/daemon_generators/nanite_agent/nanite_agent_generator.rb +1 -1
- data/lib/daemon_kit/application.rb +4 -2
- data/lib/daemon_kit/config.rb +5 -0
- data/lib/daemon_kit/error_handlers/base.rb +32 -0
- data/lib/daemon_kit/error_handlers/hoptoad.rb +61 -0
- data/lib/daemon_kit/error_handlers/mail.rb +48 -0
- data/lib/daemon_kit/initializer.rb +66 -25
- data/lib/daemon_kit/nanite/agent.rb +2 -2
- data/lib/daemon_kit/safety.rb +85 -0
- data/lib/daemon_kit/tasks/environment.rake +9 -0
- data/lib/daemon_kit/tasks/framework.rake +34 -3
- data/lib/daemon_kit.rb +2 -1
- data/rubygems_generators/install_rspec/templates/spec/spec_helper.rb +1 -0
- data/rubygems_generators/install_rspec/templates/tasks/rspec.rake +1 -1
- data/test/test_amqp_generator.rb +1 -1
- data/test/test_daemon-kit_generator.rb +4 -2
- data/test/test_jabber_generator.rb +1 -1
- metadata +9 -3
data/History.txt
CHANGED
@@ -1,3 +1,12 @@
|
|
1
|
+
== 0.1.6 2009-05-13
|
2
|
+
|
3
|
+
* DaemonKit::Safety class to handle the trapping and logging of
|
4
|
+
exceptions, as well as email notifications or Hoptoad notifications.
|
5
|
+
* New config/pre-daemonize and config/post-daemonize structure
|
6
|
+
* New tasks to simplify upgrading daemon-kit projects
|
7
|
+
* Fixed some other annoyances and bugs
|
8
|
+
* Bigger TODO list
|
9
|
+
|
1
10
|
== 0.1.5 2009-05-07
|
2
11
|
|
3
12
|
* DaemonKit::Config class to easy the use of YAML configs internally,
|
data/Manifest.txt
CHANGED
@@ -14,7 +14,8 @@ app_generators/daemon_kit/templates/config/environment.rb
|
|
14
14
|
app_generators/daemon_kit/templates/config/environments/development.rb
|
15
15
|
app_generators/daemon_kit/templates/config/environments/production.rb
|
16
16
|
app_generators/daemon_kit/templates/config/environments/test.rb
|
17
|
-
app_generators/daemon_kit/templates/config/
|
17
|
+
app_generators/daemon_kit/templates/config/post-daemonize/readme
|
18
|
+
app_generators/daemon_kit/templates/config/pre-daemonize/readme
|
18
19
|
app_generators/daemon_kit/templates/lib/daemon.rb
|
19
20
|
app_generators/daemon_kit/templates/libexec/daemon.erb
|
20
21
|
bin/daemon_kit
|
@@ -43,12 +44,17 @@ lib/daemon_kit/amqp.rb
|
|
43
44
|
lib/daemon_kit/application.rb
|
44
45
|
lib/daemon_kit/config.rb
|
45
46
|
lib/daemon_kit/cron.rb
|
47
|
+
lib/daemon_kit/error_handlers/base.rb
|
48
|
+
lib/daemon_kit/error_handlers/hoptoad.rb
|
49
|
+
lib/daemon_kit/error_handlers/mail.rb
|
46
50
|
lib/daemon_kit/initializer.rb
|
47
51
|
lib/daemon_kit/jabber.rb
|
48
52
|
lib/daemon_kit/nanite.rb
|
49
53
|
lib/daemon_kit/nanite/agent.rb
|
50
54
|
lib/daemon_kit/patches/force_kill_wait.rb
|
55
|
+
lib/daemon_kit/safety.rb
|
51
56
|
lib/daemon_kit/tasks.rb
|
57
|
+
lib/daemon_kit/tasks/environment.rake
|
52
58
|
lib/daemon_kit/tasks/framework.rake
|
53
59
|
rubygems_generators/install_rspec/USAGE
|
54
60
|
rubygems_generators/install_rspec/install_rspec_generator.rb
|
data/TODO.txt
CHANGED
@@ -4,7 +4,7 @@ DaemonKit TODO List
|
|
4
4
|
This is purely a drop in the bucket of what has to come...
|
5
5
|
|
6
6
|
* [DONE] Easy way to trap signals
|
7
|
-
* Error handling to the degree Rails does
|
7
|
+
* [IN PROGRESS] Error handling to the degree Rails does
|
8
8
|
* Easy configuration of an ORM of choice, including patching it if needed (ActiveRecord *cough*)
|
9
9
|
* Improved generators for creating skeleton daemons:
|
10
10
|
* [DONE] Jabber bot
|
@@ -14,6 +14,7 @@ This is purely a drop in the bucket of what has to come...
|
|
14
14
|
* Queue (SQS, AMQP, etc) pollers
|
15
15
|
* Rake tasks for generating:
|
16
16
|
* god configs
|
17
|
+
* Sys-V style init scripts
|
17
18
|
* Pre-built capistrano configs for easy deployment
|
18
19
|
* Support for dropping privileges
|
19
20
|
* Support for chroot'ing
|
@@ -60,15 +60,19 @@ class DaemonKitGenerator < RubiGen::Base
|
|
60
60
|
m.template "config/environment.rb", "config/environment.rb"
|
61
61
|
m.directory "config/environments"
|
62
62
|
%w{ development test production }.each { |f| m.file "config/environments/#{f}.rb", "config/environments/#{f}.rb" }
|
63
|
-
m.directory "config/
|
64
|
-
m.file "config/
|
63
|
+
m.directory "config/pre-daemonize"
|
64
|
+
m.file "config/pre-daemonize/readme", "config/pre-daemonize/readme"
|
65
|
+
m.directory "config/post-daemonize"
|
66
|
+
m.file "config/post-daemonize/readme", "config/post-daemonize/readme"
|
65
67
|
|
66
68
|
# Libraries
|
67
69
|
m.directory "lib"
|
68
70
|
m.file "lib/daemon.rb", "lib/#{daemon_name}.rb"
|
69
71
|
|
70
|
-
#
|
72
|
+
# Tasks
|
71
73
|
m.directory "tasks"
|
74
|
+
|
75
|
+
# Tests
|
72
76
|
m.dependency "install_rspec", [daemon_name], :destination => destination_root, :collision => :force
|
73
77
|
|
74
78
|
# Others
|
@@ -16,4 +16,8 @@ DaemonKit::Initializer.run do |config|
|
|
16
16
|
|
17
17
|
# Force the daemon to be killed after X seconds from asking it to
|
18
18
|
# config.force_kill_wait = 30
|
19
|
+
|
20
|
+
# Configure the safety net (see DaemonKit::Safety)
|
21
|
+
# config.safety_net.handler = :mail # (or :hoptoad )
|
22
|
+
# config.safety_net.mail.host = 'localhost'
|
19
23
|
end
|
@@ -1,7 +1,8 @@
|
|
1
1
|
# You can place files in here to be loaded before the code is daemonized.
|
2
2
|
#
|
3
3
|
# DaemonKit looks for a file named '<config.daemon_name>.rb' and loads
|
4
|
-
# that file
|
4
|
+
# that file first, and inside a DaemonKit::Initializer block. The
|
5
|
+
# remaning files then simply required into the running process.
|
5
6
|
#
|
6
7
|
# These files are mostly useful for operations that should fail blatantly
|
7
8
|
# before daemonizing, like loading gems.
|
@@ -1 +1,2 @@
|
|
1
|
-
# Your starting point for daemon specific classes
|
1
|
+
# Your starting point for daemon specific classes. This directory is
|
2
|
+
# already included in your load path, so no need to specify it.
|
@@ -15,7 +15,7 @@ class AmqpGenerator < RubiGen::Base
|
|
15
15
|
record do |m|
|
16
16
|
# Ensure appropriate folder(s) exists
|
17
17
|
m.directory ''
|
18
|
-
|
18
|
+
|
19
19
|
# Create stubs
|
20
20
|
# m.template "template.rb.erb", "some_file_after_erb.rb"
|
21
21
|
# m.template_copy_each ["template.rb", "template2.rb"]
|
@@ -32,7 +32,7 @@ class AmqpGenerator < RubiGen::Base
|
|
32
32
|
|
33
33
|
# Copy over our daemon
|
34
34
|
m.directory 'libexec'
|
35
|
-
m.template 'libexec/daemon.rb', "libexec/#{name}.rb"
|
35
|
+
m.template 'libexec/daemon.rb', "libexec/#{name}-daemon.rb"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
@@ -23,7 +23,7 @@ class CronGenerator < RubiGen::Base
|
|
23
23
|
# m.file "file", "some_file_copied"
|
24
24
|
# m.file_copy_each ["path/to/file", "path/to/file2"]
|
25
25
|
# m.file_copy_each ["path/to/file", "path/to/file2"], "some/path"
|
26
|
-
|
26
|
+
|
27
27
|
# Copy over configs
|
28
28
|
m.directory 'config'
|
29
29
|
m.directory 'config/initializers'
|
@@ -31,7 +31,7 @@ class CronGenerator < RubiGen::Base
|
|
31
31
|
|
32
32
|
# Copy over our daemon
|
33
33
|
m.directory 'libexec'
|
34
|
-
m.template 'libexec/daemon.rb', "libexec/#{name}.rb"
|
34
|
+
m.template 'libexec/daemon.rb', "libexec/#{name}-daemon.rb"
|
35
35
|
end
|
36
36
|
end
|
37
37
|
|
@@ -23,7 +23,7 @@ class JabberGenerator < RubiGen::Base
|
|
23
23
|
# m.file "file", "some_file_copied"
|
24
24
|
# m.file_copy_each ["path/to/file", "path/to/file2"]
|
25
25
|
# m.file_copy_each ["path/to/file", "path/to/file2"], "some/path"
|
26
|
-
|
26
|
+
|
27
27
|
# Copy over our configs
|
28
28
|
m.directory 'config'
|
29
29
|
m.template 'config/jabber.yml', 'config/jabber.yml'
|
@@ -32,7 +32,7 @@ class JabberGenerator < RubiGen::Base
|
|
32
32
|
|
33
33
|
# Copy over our daemon
|
34
34
|
m.directory 'libexec'
|
35
|
-
m.template 'libexec/daemon.rb', "libexec/#{name}.rb"
|
35
|
+
m.template 'libexec/daemon.rb', "libexec/#{name}-daemon.rb"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
|
@@ -14,8 +14,8 @@ module DaemonKit
|
|
14
14
|
app_name = DaemonKit.configuration.daemon_name || File.basename( file )
|
15
15
|
options = { :backtrace => true, :log_output => true, :app_name => app_name }
|
16
16
|
|
17
|
-
options[:dir_mode] = DaemonKit.configuration.dir_mode
|
18
|
-
options[:dir] = DaemonKit.configuration.dir
|
17
|
+
options[:dir_mode] = DaemonKit.configuration.dir_mode
|
18
|
+
options[:dir] = DaemonKit.configuration.dir
|
19
19
|
options[:multiple] = DaemonKit.configuration.multiple
|
20
20
|
options[:force_kill_wait] = DaemonKit.configuration.force_kill_wait if DaemonKit.configuration.force_kill_wait
|
21
21
|
|
@@ -26,6 +26,8 @@ module DaemonKit
|
|
26
26
|
# initialization process
|
27
27
|
def running!
|
28
28
|
DaemonKit::Initializer.continue!
|
29
|
+
|
30
|
+
yield DaemonKit.configuration if block_given?
|
29
31
|
end
|
30
32
|
|
31
33
|
end
|
data/lib/daemon_kit/config.rb
CHANGED
@@ -29,6 +29,11 @@ module DaemonKit
|
|
29
29
|
new( YAML.load_file( path ) )
|
30
30
|
end
|
31
31
|
|
32
|
+
# Return the +config+.yml file as a raw hash.
|
33
|
+
def hash( config, symbolize = false )
|
34
|
+
self.load( config ).to_h( symbolize )
|
35
|
+
end
|
36
|
+
|
32
37
|
end
|
33
38
|
|
34
39
|
# Expects a hash, looks for DAEMON_ENV key
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module DaemonKit
|
2
|
+
module ErrorHandlers
|
3
|
+
# Error handlers in DaemonKit are used by the #Safety class. Any
|
4
|
+
# error handler has to support the interface provided by this
|
5
|
+
# class. It's also required that safety handlers implement a
|
6
|
+
# singleton approach (handled by default by #Base).
|
7
|
+
class Base
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
@instance = nil
|
12
|
+
|
13
|
+
def instance
|
14
|
+
@instance ||= new
|
15
|
+
end
|
16
|
+
private :new
|
17
|
+
|
18
|
+
# When we're inherited, immediately register the handler with
|
19
|
+
# the safety net
|
20
|
+
def inherited( child ) #:nodoc:
|
21
|
+
Safety.register_error_handler( child )
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
# Error handlers should overwrite this method and implement
|
26
|
+
# their own reporting method.
|
27
|
+
def handle_exception( exception )
|
28
|
+
raise NoMethodError, "Error handler doesn't support #handle_exception"
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,61 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module DaemonKit
|
4
|
+
module ErrorHandlers
|
5
|
+
# Error reporting via Hoptoad.
|
6
|
+
class Hoptoad < Base
|
7
|
+
|
8
|
+
# Your hoptoad API key
|
9
|
+
@api_key = nil
|
10
|
+
attr_accessor :api_key
|
11
|
+
|
12
|
+
def handle_exception( exception )
|
13
|
+
headers = {
|
14
|
+
'Content-type' => 'application/x-yaml',
|
15
|
+
'Accept' => 'text/xml, application/xml'
|
16
|
+
}
|
17
|
+
|
18
|
+
http = Net::HTTP.new( url.host, url.port )
|
19
|
+
data = clean_exception( exception )
|
20
|
+
|
21
|
+
response = begin
|
22
|
+
http.post( url.path, data.to_yaml, headers )
|
23
|
+
rescue TimoutError => e
|
24
|
+
DaemonKit.logger.error("Timeout while contacting the Hoptoad server.")
|
25
|
+
nil
|
26
|
+
end
|
27
|
+
case response
|
28
|
+
when Net::HTTPSuccess then
|
29
|
+
DaemonKit.logger.info "Hoptoad Success: #{response.class}"
|
30
|
+
else
|
31
|
+
DaemonKit.logger.error "Hoptoad Failure: #{response.class}\n#{response.body if response.respond_to? :body}"
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
def url
|
36
|
+
URI.parse("http://hoptoadapp.com/notices/")
|
37
|
+
end
|
38
|
+
|
39
|
+
def clean_exception( exception )
|
40
|
+
data = {
|
41
|
+
:api_key => self.api_key,
|
42
|
+
:error_class => exception.class.name,
|
43
|
+
:error_message => "#{exception.class.name}: #{exception.message}",
|
44
|
+
:backtrace => exception.backtrace,
|
45
|
+
:environment => ENV.to_hash,
|
46
|
+
:request => [],
|
47
|
+
:session => []
|
48
|
+
}
|
49
|
+
|
50
|
+
stringify_keys( data )
|
51
|
+
end
|
52
|
+
|
53
|
+
def stringify_keys(hash) #:nodoc:
|
54
|
+
hash.inject({}) do |h, pair|
|
55
|
+
h[pair.first.to_s] = pair.last.is_a?(Hash) ? stringify_keys(pair.last) : pair.last
|
56
|
+
h
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
require 'net/smtp'
|
2
|
+
|
3
|
+
module DaemonKit
|
4
|
+
module ErrorHandlers
|
5
|
+
# Send an email notification of the exception via SMTP
|
6
|
+
class Mail < Base
|
7
|
+
|
8
|
+
# SMTP hostname
|
9
|
+
@host = 'localhost'
|
10
|
+
attr_accessor :host
|
11
|
+
|
12
|
+
# Recipients of the notification
|
13
|
+
@recipients = []
|
14
|
+
attr_accessor :recipients
|
15
|
+
|
16
|
+
# Subject prefix
|
17
|
+
@prefix = '[DAEMON-KIT]'
|
18
|
+
attr_accessor :prefix
|
19
|
+
|
20
|
+
# Sender address
|
21
|
+
@sender = 'daemon-kit'
|
22
|
+
attr_accessor :sender
|
23
|
+
|
24
|
+
def handle_exception( exception )
|
25
|
+
email = <<EOF
|
26
|
+
To: #{self.recipients.map { |r| '<' + r + '>' }.join(', ')}
|
27
|
+
From: <#{self.sender}>
|
28
|
+
Subject: #{self.prefix} #{exception.message}
|
29
|
+
Date: #{Time.now}
|
30
|
+
|
31
|
+
DaemonKit caught an exception inside #{DaemonKit.configuration.daemon_name}.
|
32
|
+
|
33
|
+
Message: #{exception.message}
|
34
|
+
Backtrace:
|
35
|
+
#{exception.backtrace.join("\n ")}
|
36
|
+
|
37
|
+
Environment: #{ENV.inspect}
|
38
|
+
EOF
|
39
|
+
begin
|
40
|
+
Net::SMTP.start( self.host ) do |smtp|
|
41
|
+
smtp.send_message( email, self.sender, self.recipients )
|
42
|
+
end
|
43
|
+
rescue
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
@@ -29,16 +29,23 @@ module DaemonKit
|
|
29
29
|
def trap( *args, &block )
|
30
30
|
self.configuration.trap( *args, &block )
|
31
31
|
end
|
32
|
-
|
32
|
+
|
33
|
+
def framework_root
|
34
|
+
File.join( File.dirname(__FILE__), '..', '..' )
|
35
|
+
end
|
36
|
+
|
37
|
+
def root
|
38
|
+
DAEMON_ROOT
|
39
|
+
end
|
33
40
|
end
|
34
|
-
|
41
|
+
|
35
42
|
|
36
43
|
# This class does all the nightmare work of setting up a working
|
37
44
|
# environment for your daemon.
|
38
45
|
class Initializer
|
39
46
|
|
40
47
|
attr_reader :configuration
|
41
|
-
|
48
|
+
|
42
49
|
def self.run( configuration = Configuration.new )
|
43
50
|
yield configuration if block_given?
|
44
51
|
initializer = new configuration
|
@@ -55,25 +62,29 @@ module DaemonKit
|
|
55
62
|
DaemonKit.logger.warn "Shutting down"
|
56
63
|
exit
|
57
64
|
end
|
58
|
-
|
65
|
+
|
59
66
|
def initialize( configuration )
|
60
67
|
@configuration = configuration
|
61
68
|
end
|
62
69
|
|
63
70
|
def before_daemonize
|
64
71
|
DaemonKit.configuration = @configuration
|
65
|
-
|
72
|
+
|
66
73
|
set_load_path
|
67
74
|
load_gems
|
68
75
|
load_patches
|
69
76
|
load_environment
|
77
|
+
load_predaemonize_configs
|
70
78
|
end
|
71
79
|
|
72
80
|
def after_daemonize
|
73
81
|
initialize_logger
|
74
82
|
initialize_signal_traps
|
83
|
+
|
84
|
+
include_core_lib
|
85
|
+
load_postdaemonize_configs
|
75
86
|
end
|
76
|
-
|
87
|
+
|
77
88
|
def set_load_path
|
78
89
|
configuration.load_paths.each do |d|
|
79
90
|
$:.unshift( "#{DAEMON_ROOT}/#{d}" ) if File.directory?( "#{DAEMON_ROOT}/#{d}" )
|
@@ -81,7 +92,7 @@ module DaemonKit
|
|
81
92
|
end
|
82
93
|
|
83
94
|
def load_gems
|
84
|
-
|
95
|
+
|
85
96
|
end
|
86
97
|
|
87
98
|
def load_patches
|
@@ -93,22 +104,36 @@ module DaemonKit
|
|
93
104
|
def load_environment
|
94
105
|
return if @environment_loaded
|
95
106
|
@environment_loaded = true
|
96
|
-
|
107
|
+
|
97
108
|
config = configuration
|
98
|
-
|
109
|
+
|
99
110
|
eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
|
100
|
-
|
111
|
+
|
101
112
|
eval(IO.read(configuration.daemon_initializer), binding, configuration.daemon_initializer) if File.exist?( configuration.daemon_initializer )
|
102
113
|
end
|
103
114
|
|
115
|
+
def load_predaemonize_configs
|
116
|
+
Dir[ File.join( DAEMON_ROOT, 'config', 'pre-daemonize', '*.rb' ) ].each do |f|
|
117
|
+
next if File.basename( f ) == File.basename( configuration.daemon_initializer )
|
118
|
+
|
119
|
+
require f
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def load_postdaemonize_configs
|
124
|
+
Dir[ File.join( DAEMON_ROOT, 'config', 'post-daemonize', '*.rb' ) ].each do |f|
|
125
|
+
require f
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
104
129
|
def initialize_logger
|
105
130
|
return if DaemonKit.logger
|
106
|
-
|
131
|
+
|
107
132
|
unless logger = configuration.logger
|
108
133
|
logger = Logger.new( configuration.log_path )
|
109
134
|
logger.level = configuration.log_level
|
110
135
|
end
|
111
|
-
|
136
|
+
|
112
137
|
DaemonKit.logger = logger
|
113
138
|
|
114
139
|
configuration.trap("USR1") {
|
@@ -128,9 +153,14 @@ module DaemonKit
|
|
128
153
|
configuration.trap( 'INT', term_proc )
|
129
154
|
configuration.trap( 'TERM', term_proc )
|
130
155
|
end
|
131
|
-
|
156
|
+
|
157
|
+
def include_core_lib
|
158
|
+
if File.exists?( core_lib = File.join( DAEMON_ROOT, 'lib', configuration.daemon_name + '.rb' ) )
|
159
|
+
require core_lib
|
160
|
+
end
|
161
|
+
end
|
132
162
|
end
|
133
|
-
|
163
|
+
|
134
164
|
# Holds our various configuration values
|
135
165
|
class Configuration
|
136
166
|
# Root to the daemon
|
@@ -145,7 +175,7 @@ module DaemonKit
|
|
145
175
|
# Path to the log file, defaults to 'log/<environment>.log'
|
146
176
|
attr_accessor :log_path
|
147
177
|
|
148
|
-
# :system,
|
178
|
+
# :system,
|
149
179
|
attr_accessor :dir_mode
|
150
180
|
|
151
181
|
# Path to the log file, defaults to 'log/<environment>.log'
|
@@ -166,9 +196,13 @@ module DaemonKit
|
|
166
196
|
# Collection of signal traps
|
167
197
|
attr_reader :signal_traps
|
168
198
|
|
199
|
+
# Our safety net (#Safety) instance
|
200
|
+
attr_accessor :safety_net
|
201
|
+
|
169
202
|
def initialize
|
170
203
|
set_root_path!
|
171
|
-
|
204
|
+
set_daemon_defaults!
|
205
|
+
|
172
206
|
self.load_paths = default_load_paths
|
173
207
|
self.log_level = default_log_level
|
174
208
|
self.log_path = default_log_path
|
@@ -176,6 +210,8 @@ module DaemonKit
|
|
176
210
|
self.multiple = false
|
177
211
|
self.force_kill_wait = false
|
178
212
|
|
213
|
+
self.safety_net = DaemonKit::Safety.instance
|
214
|
+
|
179
215
|
@signal_traps = {}
|
180
216
|
end
|
181
217
|
|
@@ -192,25 +228,25 @@ module DaemonKit
|
|
192
228
|
def daemon_initializer
|
193
229
|
"#{root_path}/config/initializers/#{self.daemon_name}.rb"
|
194
230
|
end
|
195
|
-
|
231
|
+
|
196
232
|
# Add a trap for the specified signal, can be code block or a proc
|
197
233
|
def trap( signal, proc = nil, &block )
|
198
234
|
return if proc.nil? && !block_given?
|
199
|
-
|
235
|
+
|
200
236
|
unless @signal_traps.has_key?( signal )
|
201
237
|
set_trap( signal )
|
202
238
|
end
|
203
|
-
|
239
|
+
|
204
240
|
@signal_traps[signal].unshift( proc || block )
|
205
241
|
end
|
206
|
-
|
242
|
+
|
207
243
|
protected
|
208
244
|
|
209
245
|
def run_traps( signal )
|
210
246
|
DaemonKit.logger.info "Running signal traps for #{signal}"
|
211
247
|
self.signal_traps[ signal ].each { |trap| trap.call }
|
212
248
|
end
|
213
|
-
|
249
|
+
|
214
250
|
private
|
215
251
|
|
216
252
|
def set_trap( signal )
|
@@ -218,7 +254,7 @@ module DaemonKit
|
|
218
254
|
@signal_traps[ signal ] = []
|
219
255
|
Signal.trap( signal, Proc.new { self.run_traps( signal ) } )
|
220
256
|
end
|
221
|
-
|
257
|
+
|
222
258
|
def set_root_path!
|
223
259
|
raise "DAEMON_ROOT is not set" unless defined?(::DAEMON_ROOT)
|
224
260
|
raise "DAEMON_ROOT is not a directory" unless defined?(::DAEMON_ROOT)
|
@@ -238,10 +274,15 @@ module DaemonKit
|
|
238
274
|
::DAEMON_ROOT.replace @root_path
|
239
275
|
end
|
240
276
|
|
277
|
+
def set_daemon_defaults!
|
278
|
+
self.dir_mode = :normal
|
279
|
+
self.dir = File.join( DAEMON_ROOT, 'log' )
|
280
|
+
end
|
281
|
+
|
241
282
|
def default_load_paths
|
242
283
|
[ 'lib' ]
|
243
284
|
end
|
244
|
-
|
285
|
+
|
245
286
|
def default_log_path
|
246
287
|
File.join(root_path, 'log', "#{environment}.log")
|
247
288
|
end
|
@@ -250,6 +291,6 @@ module DaemonKit
|
|
250
291
|
environment == 'production' ? Logger::INFO : Logger::DEBUG
|
251
292
|
end
|
252
293
|
end
|
253
|
-
|
254
|
-
|
294
|
+
|
295
|
+
|
255
296
|
end
|
@@ -20,7 +20,7 @@ module DaemonKit
|
|
20
20
|
end
|
21
21
|
|
22
22
|
def initialize
|
23
|
-
@config = DaemonKit::Config.load( 'nanite' )
|
23
|
+
@config = DaemonKit::Config.load( 'nanite' ).to_h( true )
|
24
24
|
|
25
25
|
config_agent
|
26
26
|
end
|
@@ -33,7 +33,7 @@ module DaemonKit
|
|
33
33
|
# Start our mapper
|
34
34
|
mapper_thread = Thread.new do
|
35
35
|
EM.run do
|
36
|
-
agent = ::Nanite.start_agent( @config
|
36
|
+
agent = ::Nanite.start_agent( @config )
|
37
37
|
block.call( agent ) if block
|
38
38
|
end
|
39
39
|
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module DaemonKit
|
2
|
+
# Provides a wrapper for running code inside a 'safety net' Any
|
3
|
+
# exceptions raised inside a safety net is handled and reported via
|
4
|
+
# loggers, email or Hoptoad.
|
5
|
+
#
|
6
|
+
# The safety net can be configured via DaemonKit.config.safety,
|
7
|
+
# which holds the only instance of the safety net.
|
8
|
+
class Safety
|
9
|
+
|
10
|
+
# Who get's notified.
|
11
|
+
@handler = nil
|
12
|
+
attr_accessor :handler
|
13
|
+
|
14
|
+
# Registered error handlers
|
15
|
+
@error_handlers = {}
|
16
|
+
attr_reader :error_handlers
|
17
|
+
|
18
|
+
class << self
|
19
|
+
|
20
|
+
# Singleton
|
21
|
+
@instance = nil
|
22
|
+
|
23
|
+
def instance
|
24
|
+
@instance ||= new
|
25
|
+
end
|
26
|
+
private :new
|
27
|
+
|
28
|
+
# Run the provided block inside a safety net.
|
29
|
+
def run(&block)
|
30
|
+
self.instance.run(&block)
|
31
|
+
end
|
32
|
+
|
33
|
+
def register_error_handler( klass )
|
34
|
+
name = klass.to_s.split('::').last.downcase
|
35
|
+
|
36
|
+
DaemonKit.logger.debug( "Registering error handler '#{name}' (#{klass})" ) if DaemonKit.logger
|
37
|
+
|
38
|
+
instance.instance_eval( <<-EOF, __FILE__, __LINE__ )
|
39
|
+
def #{name}
|
40
|
+
@#{name} ||= #{klass}.instance
|
41
|
+
end
|
42
|
+
EOF
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
# Run the provided block inside a safety net.
|
47
|
+
def run(&block)
|
48
|
+
begin
|
49
|
+
block.call
|
50
|
+
rescue => e
|
51
|
+
# Log
|
52
|
+
DaemonKit.logger.fatal "Safety net caught exception: #{e.message}"
|
53
|
+
DaemonKit.logger.fatal "Backtrace: #{e.backtrace.join("\n ")}"
|
54
|
+
|
55
|
+
get_handler.handle_exception( e ) if get_handler
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def get_handler
|
60
|
+
if @handler && self.respond_to?( @handler )
|
61
|
+
h = send( @handler )
|
62
|
+
return h if h.class.ancestors.include?( DaemonKit::ErrorHandlers::Base )
|
63
|
+
end
|
64
|
+
|
65
|
+
return nil
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
class Object
|
71
|
+
class << self
|
72
|
+
def safely(&block)
|
73
|
+
DaemonKit::Safety.run(&block)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
def safely(&block)
|
78
|
+
DaemonKit::Safety.run(&block)
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
# Load our error handlers
|
83
|
+
require 'daemon_kit/error_handlers/base'
|
84
|
+
require 'daemon_kit/error_handlers/mail'
|
85
|
+
require 'daemon_kit/error_handlers/hoptoad'
|
@@ -0,0 +1,9 @@
|
|
1
|
+
task :environment do
|
2
|
+
# This relies on the fact that rake changes the currect working
|
3
|
+
# directory to the directory where the Rakefile is located, thus
|
4
|
+
# implying DAEMON_ROOT.
|
5
|
+
DAEMON_ROOT = '.'
|
6
|
+
$daemon_kit_rake_task = true
|
7
|
+
|
8
|
+
require 'config/environment'
|
9
|
+
end
|
@@ -46,10 +46,10 @@ namespace :daemon_kit do
|
|
46
46
|
|
47
47
|
rm_rf "vendor/daemon_kit"
|
48
48
|
mkdir_p "vendor/daemon_kit"
|
49
|
-
|
49
|
+
|
50
50
|
chdir 'vendor/daemon_kit' do
|
51
51
|
latest_revision = YAML.load(open(commits))["commits"].first["id"]
|
52
|
-
|
52
|
+
|
53
53
|
puts "Downloading DaemonKit from #{url}"
|
54
54
|
File.open('daemon-kit.zip', 'wb') do |dst|
|
55
55
|
open url do |src|
|
@@ -70,6 +70,37 @@ namespace :daemon_kit do
|
|
70
70
|
touch "REVISION_#{latest_revision}"
|
71
71
|
end
|
72
72
|
end
|
73
|
-
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
desc "Upgrade your local files for a daemon after upgrading daemon-kit"
|
77
|
+
task :upgrade => 'environment' do
|
78
|
+
# Run these
|
79
|
+
%w{ initializers }.each do |t|
|
80
|
+
Rake::Task["daemon_kit:upgrade:#{t}"].invoke
|
81
|
+
end
|
82
|
+
|
83
|
+
puts
|
84
|
+
puts "#{DaemonKit.configuration.daemon_name} has been upgraded."
|
74
85
|
end
|
86
|
+
|
87
|
+
namespace :upgrade do
|
88
|
+
# Upgrade the initializers
|
89
|
+
task :initializers do
|
90
|
+
if File.directory?( File.join(DaemonKit.root, 'config', 'initializers') )
|
91
|
+
mv File.join(DaemonKit.root, 'config', 'initializers'), File.join(DAEMON_ROOT, 'config', 'pre-daemonize')
|
92
|
+
copy_framework_template( 'config', 'pre-daemonize', 'readme' )
|
93
|
+
end
|
94
|
+
|
95
|
+
unless File.directory?( File.join(DAEMON_ROOT, 'config', 'post-daemonize') )
|
96
|
+
mkdir_p File.join(DAEMON_ROOT, 'config', 'post-daemonize')
|
97
|
+
copy_framework_template( 'config', 'post-daemonize', 'readme' )
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
def copy_framework_template( *args )
|
104
|
+
src_dir = File.join(DaemonKit.framework_root, 'app_generators', 'daemon_kit', 'templates')
|
105
|
+
cp File.join( src_dir, *args ), File.join( DaemonKit.root, *args )
|
75
106
|
end
|
data/lib/daemon_kit.rb
CHANGED
@@ -4,7 +4,7 @@ $:.unshift(File.dirname(__FILE__)) unless
|
|
4
4
|
require 'rubygems'
|
5
5
|
|
6
6
|
module DaemonKit
|
7
|
-
VERSION = '0.1.
|
7
|
+
VERSION = '0.1.6'
|
8
8
|
|
9
9
|
autoload :Initializer, 'daemon_kit/initializer'
|
10
10
|
autoload :Application, 'daemon_kit/application'
|
@@ -13,4 +13,5 @@ module DaemonKit
|
|
13
13
|
autoload :Jabber, 'daemon_kit/jabber'
|
14
14
|
autoload :AMQP, 'daemon_kit/amqp'
|
15
15
|
autoload :Nanite, 'daemon_kit/nanite'
|
16
|
+
autoload :Safety, 'daemon_kit/safety'
|
16
17
|
end
|
data/test/test_amqp_generator.rb
CHANGED
@@ -33,7 +33,7 @@ class TestAmqpGenerator < Test::Unit::TestCase
|
|
33
33
|
assert_directory_exists "config/initializers"
|
34
34
|
assert_generated_file "config/amqp.yml"
|
35
35
|
assert_generated_file "config/initializers/myapp.rb"
|
36
|
-
assert_generated_file "libexec/myapp.rb"
|
36
|
+
assert_generated_file "libexec/myapp-daemon.rb"
|
37
37
|
end
|
38
38
|
|
39
39
|
private
|
@@ -40,8 +40,10 @@ class TestDaemonKitGenerator < Test::Unit::TestCase
|
|
40
40
|
assert_generated_file "config/environments/development.rb"
|
41
41
|
assert_generated_file "config/environments/test.rb"
|
42
42
|
assert_generated_file "config/environments/production.rb"
|
43
|
-
assert_directory_exists "config/
|
44
|
-
assert_generated_file "config/
|
43
|
+
assert_directory_exists "config/pre-daemonize"
|
44
|
+
assert_generated_file "config/pre-daemonize/readme"
|
45
|
+
assert_directory_exists "config/post-daemonize"
|
46
|
+
assert_generated_file "config/post-daemonize/readme"
|
45
47
|
assert_directory_exists "lib"
|
46
48
|
assert_generated_file "lib/#{daemon_name}.rb"
|
47
49
|
assert_directory_exists "libexec"
|
@@ -34,7 +34,7 @@ class TestJabberGenerator < Test::Unit::TestCase
|
|
34
34
|
assert_directory_exists "config/initializers"
|
35
35
|
assert_generated_file "config/initializers/myapp.rb"
|
36
36
|
assert_directory_exists "libexec"
|
37
|
-
assert_generated_file "libexec/myapp.rb"
|
37
|
+
assert_generated_file "libexec/myapp-daemon.rb"
|
38
38
|
end
|
39
39
|
|
40
40
|
private
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: kennethkalmer-daemon-kit
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.6
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Kenneth Kalmer
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2009-05-
|
12
|
+
date: 2009-05-13 00:00:00 -07:00
|
13
13
|
default_executable: daemon_kit
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
@@ -81,7 +81,8 @@ files:
|
|
81
81
|
- app_generators/daemon_kit/templates/config/environments/development.rb
|
82
82
|
- app_generators/daemon_kit/templates/config/environments/production.rb
|
83
83
|
- app_generators/daemon_kit/templates/config/environments/test.rb
|
84
|
-
- app_generators/daemon_kit/templates/config/
|
84
|
+
- app_generators/daemon_kit/templates/config/post-daemonize/readme
|
85
|
+
- app_generators/daemon_kit/templates/config/pre-daemonize/readme
|
85
86
|
- app_generators/daemon_kit/templates/lib/daemon.rb
|
86
87
|
- app_generators/daemon_kit/templates/libexec/daemon.erb
|
87
88
|
- bin/daemon_kit
|
@@ -110,12 +111,17 @@ files:
|
|
110
111
|
- lib/daemon_kit/application.rb
|
111
112
|
- lib/daemon_kit/config.rb
|
112
113
|
- lib/daemon_kit/cron.rb
|
114
|
+
- lib/daemon_kit/error_handlers/base.rb
|
115
|
+
- lib/daemon_kit/error_handlers/hoptoad.rb
|
116
|
+
- lib/daemon_kit/error_handlers/mail.rb
|
113
117
|
- lib/daemon_kit/initializer.rb
|
114
118
|
- lib/daemon_kit/jabber.rb
|
115
119
|
- lib/daemon_kit/nanite.rb
|
116
120
|
- lib/daemon_kit/nanite/agent.rb
|
117
121
|
- lib/daemon_kit/patches/force_kill_wait.rb
|
122
|
+
- lib/daemon_kit/safety.rb
|
118
123
|
- lib/daemon_kit/tasks.rb
|
124
|
+
- lib/daemon_kit/tasks/environment.rake
|
119
125
|
- lib/daemon_kit/tasks/framework.rake
|
120
126
|
- rubygems_generators/install_rspec/USAGE
|
121
127
|
- rubygems_generators/install_rspec/install_rspec_generator.rb
|