apphunkd 0.9.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (204) hide show
  1. data/.document +5 -0
  2. data/.gitignore +22 -0
  3. data/LICENSE +20 -0
  4. data/README.rdoc +18 -0
  5. data/Rakefile +78 -0
  6. data/TODO +1 -0
  7. data/VERSION +1 -0
  8. data/apphunkd.gemspec +258 -0
  9. data/bin/apphunkd +4 -0
  10. data/config/arguments.rb +12 -0
  11. data/config/boot.rb +68 -0
  12. data/config/environment.rb +23 -0
  13. data/config/environments/development.rb +2 -0
  14. data/config/environments/production.rb +2 -0
  15. data/config/environments/test.rb +2 -0
  16. data/config/post-daemonize/readme +5 -0
  17. data/config/pre-daemonize/readme +12 -0
  18. data/config/pre-daemonize/requires.rb +2 -0
  19. data/lib/apphunkd.rb +25 -0
  20. data/lib/apphunkd/api.rb +5 -0
  21. data/lib/apphunkd/api/service.rb +27 -0
  22. data/lib/apphunkd/queue.rb +96 -0
  23. data/lib/apphunkd/remote.rb +29 -0
  24. data/lib/apphunkd/remote/result.rb +15 -0
  25. data/libexec/apphunkd-daemon.rb +13 -0
  26. data/script/console +3 -0
  27. data/script/destroy +14 -0
  28. data/script/generate +14 -0
  29. data/spec/lib/apphunkd/api/service_spec.rb +47 -0
  30. data/spec/lib/apphunkd/queue_spec.rb +129 -0
  31. data/spec/lib/apphunkd/remote_spec.rb +61 -0
  32. data/spec/lib/apphunkd_spec.rb +50 -0
  33. data/spec/spec.opts +1 -0
  34. data/spec/spec_helper.rb +13 -0
  35. data/support/apphunkd.initd +47 -0
  36. data/support/apphunkd.monitrc +3 -0
  37. data/tasks/rspec.rake +21 -0
  38. data/vendor/daemon-kit/Configuration.txt +102 -0
  39. data/vendor/daemon-kit/Deployment.txt +113 -0
  40. data/vendor/daemon-kit/History.txt +97 -0
  41. data/vendor/daemon-kit/Logging.txt +92 -0
  42. data/vendor/daemon-kit/Manifest.txt +166 -0
  43. data/vendor/daemon-kit/PostInstall.txt +6 -0
  44. data/vendor/daemon-kit/README.rdoc +130 -0
  45. data/vendor/daemon-kit/Rakefile +37 -0
  46. data/vendor/daemon-kit/RuoteParticipants.txt +113 -0
  47. data/vendor/daemon-kit/TODO.txt +37 -0
  48. data/vendor/daemon-kit/app_generators/daemon_kit/USAGE +7 -0
  49. data/vendor/daemon-kit/app_generators/daemon_kit/daemon_kit_generator.rb +161 -0
  50. data/vendor/daemon-kit/app_generators/daemon_kit/templates/README +48 -0
  51. data/vendor/daemon-kit/app_generators/daemon_kit/templates/Rakefile +6 -0
  52. data/vendor/daemon-kit/app_generators/daemon_kit/templates/bin/daemon.erb +7 -0
  53. data/vendor/daemon-kit/app_generators/daemon_kit/templates/config/arguments.rb +12 -0
  54. data/vendor/daemon-kit/app_generators/daemon_kit/templates/config/boot.rb +68 -0
  55. data/vendor/daemon-kit/app_generators/daemon_kit/templates/config/environment.rb +23 -0
  56. data/vendor/daemon-kit/app_generators/daemon_kit/templates/config/environments/development.rb +2 -0
  57. data/vendor/daemon-kit/app_generators/daemon_kit/templates/config/environments/production.rb +2 -0
  58. data/vendor/daemon-kit/app_generators/daemon_kit/templates/config/environments/test.rb +2 -0
  59. data/vendor/daemon-kit/app_generators/daemon_kit/templates/config/post-daemonize/readme +5 -0
  60. data/vendor/daemon-kit/app_generators/daemon_kit/templates/config/pre-daemonize/readme +12 -0
  61. data/vendor/daemon-kit/app_generators/daemon_kit/templates/lib/daemon.rb +2 -0
  62. data/vendor/daemon-kit/app_generators/daemon_kit/templates/libexec/daemon.erb +18 -0
  63. data/vendor/daemon-kit/app_generators/daemon_kit/templates/script/console +3 -0
  64. data/vendor/daemon-kit/app_generators/daemon_kit/templates/script/destroy +14 -0
  65. data/vendor/daemon-kit/app_generators/daemon_kit/templates/script/generate +14 -0
  66. data/vendor/daemon-kit/bin/daemon_kit +18 -0
  67. data/vendor/daemon-kit/daemon_generators/amqp/USAGE +5 -0
  68. data/vendor/daemon-kit/daemon_generators/amqp/amqp_generator.rb +65 -0
  69. data/vendor/daemon-kit/daemon_generators/amqp/templates/config/amqp.yml +28 -0
  70. data/vendor/daemon-kit/daemon_generators/amqp/templates/config/initializers/amqp.rb +7 -0
  71. data/vendor/daemon-kit/daemon_generators/amqp/templates/libexec/daemon.rb +37 -0
  72. data/vendor/daemon-kit/daemon_generators/cron/USAGE +5 -0
  73. data/vendor/daemon-kit/daemon_generators/cron/cron_generator.rb +64 -0
  74. data/vendor/daemon-kit/daemon_generators/cron/templates/config/initializers/cron.rb +11 -0
  75. data/vendor/daemon-kit/daemon_generators/cron/templates/libexec/daemon.rb +43 -0
  76. data/vendor/daemon-kit/daemon_generators/cucumber/USAGE +11 -0
  77. data/vendor/daemon-kit/daemon_generators/cucumber/cucumber_generator.rb +38 -0
  78. data/vendor/daemon-kit/daemon_generators/cucumber/templates/cucumber +8 -0
  79. data/vendor/daemon-kit/daemon_generators/cucumber/templates/cucumber.rake +13 -0
  80. data/vendor/daemon-kit/daemon_generators/cucumber/templates/cucumber_environment.rb +2 -0
  81. data/vendor/daemon-kit/daemon_generators/cucumber/templates/env.rb +7 -0
  82. data/vendor/daemon-kit/daemon_generators/deploy_capistrano/deploy_capistrano_generator.rb +35 -0
  83. data/vendor/daemon-kit/daemon_generators/deploy_capistrano/templates/Capfile +10 -0
  84. data/vendor/daemon-kit/daemon_generators/deploy_capistrano/templates/USAGE +10 -0
  85. data/vendor/daemon-kit/daemon_generators/deploy_capistrano/templates/config/deploy.rb +53 -0
  86. data/vendor/daemon-kit/daemon_generators/deploy_capistrano/templates/config/deploy/production.rb +6 -0
  87. data/vendor/daemon-kit/daemon_generators/deploy_capistrano/templates/config/deploy/staging.rb +6 -0
  88. data/vendor/daemon-kit/daemon_generators/deploy_capistrano/templates/config/environments/staging.rb +0 -0
  89. data/vendor/daemon-kit/daemon_generators/jabber/USAGE +5 -0
  90. data/vendor/daemon-kit/daemon_generators/jabber/jabber_generator.rb +65 -0
  91. data/vendor/daemon-kit/daemon_generators/jabber/templates/config/initializers/jabber.rb +7 -0
  92. data/vendor/daemon-kit/daemon_generators/jabber/templates/config/jabber.yml +26 -0
  93. data/vendor/daemon-kit/daemon_generators/jabber/templates/libexec/daemon.rb +27 -0
  94. data/vendor/daemon-kit/daemon_generators/nanite_agent/USAGE +5 -0
  95. data/vendor/daemon-kit/daemon_generators/nanite_agent/nanite_agent_generator.rb +68 -0
  96. data/vendor/daemon-kit/daemon_generators/nanite_agent/templates/config/initializers/nanite_agent.rb +6 -0
  97. data/vendor/daemon-kit/daemon_generators/nanite_agent/templates/config/nanite.yml +35 -0
  98. data/vendor/daemon-kit/daemon_generators/nanite_agent/templates/lib/actors/sample.rb +11 -0
  99. data/vendor/daemon-kit/daemon_generators/nanite_agent/templates/libexec/daemon.rb +31 -0
  100. data/vendor/daemon-kit/daemon_generators/rspec/USAGE +5 -0
  101. data/vendor/daemon-kit/daemon_generators/rspec/rspec_generator.rb +55 -0
  102. data/vendor/daemon-kit/daemon_generators/rspec/templates/spec.rb +11 -0
  103. data/vendor/daemon-kit/daemon_generators/rspec/templates/spec/spec.opts +1 -0
  104. data/vendor/daemon-kit/daemon_generators/rspec/templates/spec/spec_helper.rb +21 -0
  105. data/vendor/daemon-kit/daemon_generators/rspec/templates/tasks/rspec.rake +21 -0
  106. data/vendor/daemon-kit/daemon_generators/ruote/USAGE +5 -0
  107. data/vendor/daemon-kit/daemon_generators/ruote/ruote_generator.rb +67 -0
  108. data/vendor/daemon-kit/daemon_generators/ruote/templates/config/amqp.yml +30 -0
  109. data/vendor/daemon-kit/daemon_generators/ruote/templates/config/initializers/ruote.rb +13 -0
  110. data/vendor/daemon-kit/daemon_generators/ruote/templates/config/ruote.yml +23 -0
  111. data/vendor/daemon-kit/daemon_generators/ruote/templates/lib/daemon.rb +4 -0
  112. data/vendor/daemon-kit/daemon_generators/ruote/templates/lib/sample.rb +26 -0
  113. data/vendor/daemon-kit/daemon_generators/ruote/templates/libexec/daemon.rb +33 -0
  114. data/vendor/daemon-kit/lib/daemon_kit.rb +54 -0
  115. data/vendor/daemon-kit/lib/daemon_kit/abstract_logger.rb +235 -0
  116. data/vendor/daemon-kit/lib/daemon_kit/amqp.rb +38 -0
  117. data/vendor/daemon-kit/lib/daemon_kit/application.rb +187 -0
  118. data/vendor/daemon-kit/lib/daemon_kit/arguments.rb +165 -0
  119. data/vendor/daemon-kit/lib/daemon_kit/commands/console.rb +38 -0
  120. data/vendor/daemon-kit/lib/daemon_kit/config.rb +108 -0
  121. data/vendor/daemon-kit/lib/daemon_kit/console_daemon.rb +2 -0
  122. data/vendor/daemon-kit/lib/daemon_kit/core_ext.rb +1 -0
  123. data/vendor/daemon-kit/lib/daemon_kit/core_ext/configurable.rb +96 -0
  124. data/vendor/daemon-kit/lib/daemon_kit/core_ext/string.rb +22 -0
  125. data/vendor/daemon-kit/lib/daemon_kit/cron.rb +48 -0
  126. data/vendor/daemon-kit/lib/daemon_kit/cucumber/world.rb +38 -0
  127. data/vendor/daemon-kit/lib/daemon_kit/deployment/capistrano.rb +482 -0
  128. data/vendor/daemon-kit/lib/daemon_kit/em.rb +43 -0
  129. data/vendor/daemon-kit/lib/daemon_kit/error_handlers/base.rb +32 -0
  130. data/vendor/daemon-kit/lib/daemon_kit/error_handlers/hoptoad.rb +61 -0
  131. data/vendor/daemon-kit/lib/daemon_kit/error_handlers/mail.rb +85 -0
  132. data/vendor/daemon-kit/lib/daemon_kit/exceptions.rb +8 -0
  133. data/vendor/daemon-kit/lib/daemon_kit/initializer.rb +438 -0
  134. data/vendor/daemon-kit/lib/daemon_kit/jabber.rb +170 -0
  135. data/vendor/daemon-kit/lib/daemon_kit/nanite.rb +7 -0
  136. data/vendor/daemon-kit/lib/daemon_kit/nanite/agent.rb +56 -0
  137. data/vendor/daemon-kit/lib/daemon_kit/pid_file.rb +61 -0
  138. data/vendor/daemon-kit/lib/daemon_kit/ruote_participants.rb +119 -0
  139. data/vendor/daemon-kit/lib/daemon_kit/ruote_pseudo_participant.rb +68 -0
  140. data/vendor/daemon-kit/lib/daemon_kit/ruote_workitem.rb +169 -0
  141. data/vendor/daemon-kit/lib/daemon_kit/safety.rb +85 -0
  142. data/vendor/daemon-kit/lib/daemon_kit/tasks.rb +2 -0
  143. data/vendor/daemon-kit/lib/daemon_kit/tasks/environment.rake +10 -0
  144. data/vendor/daemon-kit/lib/daemon_kit/tasks/framework.rake +120 -0
  145. data/vendor/daemon-kit/lib/daemon_kit/tasks/god.rake +62 -0
  146. data/vendor/daemon-kit/lib/daemon_kit/tasks/log.rake +8 -0
  147. data/vendor/daemon-kit/lib/daemon_kit/tasks/monit.rake +29 -0
  148. data/vendor/daemon-kit/script/console +10 -0
  149. data/vendor/daemon-kit/script/destroy +14 -0
  150. data/vendor/daemon-kit/script/generate +14 -0
  151. data/vendor/daemon-kit/script/txt2html +71 -0
  152. data/vendor/daemon-kit/spec/abstract_logger_spec.rb +126 -0
  153. data/vendor/daemon-kit/spec/argument_spec.rb +70 -0
  154. data/vendor/daemon-kit/spec/config_spec.rb +79 -0
  155. data/vendor/daemon-kit/spec/configurable_spec.rb +56 -0
  156. data/vendor/daemon-kit/spec/daemon_kit_spec.rb +7 -0
  157. data/vendor/daemon-kit/spec/error_handlers_spec.rb +23 -0
  158. data/vendor/daemon-kit/spec/fixtures/env.yml +15 -0
  159. data/vendor/daemon-kit/spec/fixtures/noenv.yml +4 -0
  160. data/vendor/daemon-kit/spec/initializer_spec.rb +26 -0
  161. data/vendor/daemon-kit/spec/spec.opts +1 -0
  162. data/vendor/daemon-kit/spec/spec_helper.rb +27 -0
  163. data/vendor/daemon-kit/tasks/rspec.rake +21 -0
  164. data/vendor/daemon-kit/templates/god/god.erb +69 -0
  165. data/vendor/daemon-kit/templates/monit/monit.erb +14 -0
  166. data/vendor/daemon-kit/test/test_amqp_generator.rb +48 -0
  167. data/vendor/daemon-kit/test/test_cron_generator.rb +45 -0
  168. data/vendor/daemon-kit/test/test_daemon-kit_generator.rb +84 -0
  169. data/vendor/daemon-kit/test/test_daemon_kit_config.rb +28 -0
  170. data/vendor/daemon-kit/test/test_deploy_capistrano_generator.rb +48 -0
  171. data/vendor/daemon-kit/test/test_generator_helper.rb +29 -0
  172. data/vendor/daemon-kit/test/test_helper.rb +7 -0
  173. data/vendor/daemon-kit/test/test_jabber_generator.rb +49 -0
  174. data/vendor/daemon-kit/test/test_nanite_agent_generator.rb +49 -0
  175. data/vendor/daemon-kit/test/test_ruote_generator.rb +45 -0
  176. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail.rb +5 -0
  177. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/address.rb +426 -0
  178. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/attachments.rb +46 -0
  179. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/base64.rb +46 -0
  180. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/compat.rb +41 -0
  181. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/config.rb +67 -0
  182. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/core_extensions.rb +63 -0
  183. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/encode.rb +581 -0
  184. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/header.rb +960 -0
  185. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/index.rb +9 -0
  186. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/interface.rb +1130 -0
  187. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/loader.rb +3 -0
  188. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/mail.rb +578 -0
  189. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/mailbox.rb +495 -0
  190. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/main.rb +6 -0
  191. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/mbox.rb +3 -0
  192. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/net.rb +248 -0
  193. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/obsolete.rb +132 -0
  194. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/parser.rb +1476 -0
  195. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/port.rb +379 -0
  196. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/quoting.rb +118 -0
  197. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/require_arch.rb +58 -0
  198. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/scanner.rb +49 -0
  199. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/scanner_r.rb +261 -0
  200. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/stringio.rb +280 -0
  201. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/utils.rb +337 -0
  202. data/vendor/daemon-kit/vendor/tmail-1.2.3/tmail/version.rb +39 -0
  203. data/vendor/daemon-kit/vendor/tmail.rb +13 -0
  204. metadata +281 -0
@@ -0,0 +1,43 @@
1
+ module DaemonKit
2
+
3
+ # EventMachine forms a critical part of the daemon-kit toolset, and
4
+ # especially of daemon process developers.
5
+ #
6
+ # This class abstracts away the difficulties of managing multiple
7
+ # libraries that all utilize the event reactor.
8
+ class EM
9
+
10
+ class << self
11
+
12
+ # Start a reactor, just like classical EM.run. If the block is
13
+ # provided, the method will block and call the provided block
14
+ # argument inside the running reactor. If the block argument is
15
+ # not provided the reactor will be started in a separate thread
16
+ # and the program will continue to run after the method. All the
17
+ # signal traps are configured to shutdown the reactor when the
18
+ # daemon exists.
19
+ def run(&block)
20
+ if ::EM.reactor_running?
21
+ DaemonKit.logger.warn "EventMachine reactor already running"
22
+ block.call if block_given?
23
+
24
+ else
25
+ if block_given?
26
+ ::EM.run { block.call }
27
+ else
28
+ Thread.main[:_dk_reactor] = Thread.new { EM.run {} }
29
+ DaemonKit.trap( 'INT' ) { DaemonKit::EM.stop }
30
+ DaemonKit.trap( 'TERM' ) { DaemonKit::EM.stop }
31
+ end
32
+ end
33
+ end
34
+
35
+ # Stop the reactor
36
+ def stop
37
+ ::EM.stop_event_loop if ::EM.reactor_running?
38
+ Thread.main[:_dk_reactor].join
39
+ end
40
+ end
41
+
42
+ end
43
+ end
@@ -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,85 @@
1
+ require DaemonKit.framework_root + '/vendor/tmail'
2
+ require 'net/smtp'
3
+
4
+ module DaemonKit
5
+ module ErrorHandlers
6
+ # Send an email notification of the exception via SMTP.
7
+ class Mail < Base
8
+
9
+ # SMTP hostname
10
+ @host = 'localhost'
11
+
12
+ # SMTP port
13
+ @port = 25
14
+
15
+ # Recipients of the notification
16
+ @recipients = []
17
+
18
+ # Subject prefix
19
+ @prefix = '[DAEMON-KIT]'
20
+
21
+ # Sender address
22
+ @sender = 'daemon-kit'
23
+
24
+ # SMTP username
25
+ @username = nil
26
+
27
+ # SMTP password
28
+ @password = nil
29
+
30
+ # Authentication mechanism (:plain, :login, or :cram_md5)
31
+ @authentication = nil
32
+
33
+ # Use TLS?
34
+ @tls = false
35
+
36
+ # Domain used when talking to SMTP server
37
+ @domain = 'localhost.localdomain'
38
+
39
+ class << self
40
+ attr_accessor :host, :port, :recipients, :prefix, :sender, :username,
41
+ :password, :authentication, :tls, :domain
42
+ end
43
+
44
+ [ :host, :port, :recipients, :prefix, :sender, :username, :password,
45
+ :authentication, :tls, :domain ].each do |cm|
46
+ class_eval(<<-EOM, __FILE__, __LINE__)
47
+ def #{cm}=( val )
48
+ self.class.#{cm} = val
49
+ end
50
+ EOM
51
+ end
52
+
53
+ def handle_exception( exception )
54
+
55
+ mail = TMail::Mail.new
56
+ mail.to = self.class.recipients
57
+ mail.from = self.class.sender
58
+ mail.subject = "#{self.class.prefix} #{exception.message}"
59
+ mail.set_content_type 'text', 'plain'
60
+ mail.mime_version = '1.0'
61
+ mail.date = Time.now
62
+
63
+ mail.body = <<EOF
64
+ DaemonKit caught an exception inside #{DaemonKit.configuration.daemon_name}.
65
+
66
+ Message: #{exception.message}
67
+ Backtrace:
68
+ #{exception.backtrace.join("\n ")}
69
+
70
+ Environment: #{ENV.inspect}
71
+ EOF
72
+ begin
73
+ smtp = Net::SMTP.new( self.class.host, self.class.port )
74
+ smtp.enable_starttls_auto if self.class.tls && smtp.respond_to?(:enable_starttls_auto)
75
+ smtp.start( self.class.domain, self.class.username, self.class.password,
76
+ self.class.authentication ) do |smtp|
77
+ smtp.sendmail( mail.to_s, mail.from, mail.to )
78
+ end
79
+ rescue => e
80
+ DaemonKit.logger.error "Failed to send exception mail: #{e.message}" if DaemonKit.logger
81
+ end
82
+ end
83
+ end
84
+ end
85
+ end
@@ -0,0 +1,8 @@
1
+ module DaemonKit
2
+ # The core of daemon-kit exceptions
3
+ class Exception < ::StandardError
4
+ end
5
+
6
+ # Raised when no class is registered to process a ruote workitem
7
+ class MissingParticipant < Exception; end
8
+ end
@@ -0,0 +1,438 @@
1
+ require 'pathname'
2
+
3
+ DAEMON_ENV = (ENV['DAEMON_ENV'] || 'development').dup unless defined?(DAEMON_ENV)
4
+
5
+ # Absolute paths to the daemon_kit libraries added to $:
6
+ incdir = ( File.dirname(__FILE__) + '/..' )
7
+ absincdir = if RUBY_PLATFORM =~ /(:?mswin|mingw)/
8
+ File.expand_path( incdir )
9
+ else
10
+ File.expand_path( Pathname.new( incdir ).realpath.to_s )
11
+ end
12
+ $:.unshift absincdir unless $:.include?( absincdir )
13
+
14
+ require 'daemon_kit'
15
+
16
+ module DaemonKit
17
+
18
+ class << self
19
+
20
+ def configuration
21
+ @configuration
22
+ end
23
+
24
+ def configuration=( configuration )
25
+ @configuration = configuration
26
+ end
27
+
28
+ def arguments
29
+ @arguments
30
+ end
31
+
32
+ def arguments=( args )
33
+ @arguments = args
34
+ end
35
+
36
+ def trap( *args, &block )
37
+ self.configuration.trap( *args, &block )
38
+ end
39
+
40
+ def at_shutdown( &block )
41
+ self.configuration.at_shutdown( &block )
42
+ end
43
+
44
+ end
45
+
46
+
47
+ # This class does all the nightmare work of setting up a working
48
+ # environment for your daemon.
49
+ class Initializer
50
+
51
+ attr_reader :configuration
52
+
53
+ def self.run
54
+ configuration = DaemonKit.configuration || Configuration.new
55
+
56
+ yield configuration if block_given?
57
+ initializer = new configuration
58
+ initializer.before_daemonize
59
+ initializer
60
+ end
61
+
62
+ def self.continue!
63
+ initializer = new DaemonKit.configuration
64
+ initializer.after_daemonize
65
+ end
66
+
67
+ def self.shutdown( clean = false )
68
+ return unless $daemon_kit_shutdown_hooks_ran.nil?
69
+ $daemon_kit_shutdown_hooks_ran = true
70
+
71
+ DaemonKit.logger.info "Running shutdown hooks"
72
+
73
+ DaemonKit.configuration.shutdown_hooks.each do |hook|
74
+ begin
75
+ hook.call
76
+ rescue => e
77
+ DaemonKit.logger.exception( e )
78
+ end
79
+ end
80
+
81
+ log_exceptions if DaemonKit.configuration.backtraces && !clean
82
+
83
+ DaemonKit.logger.warn "Shutting down #{DaemonKit.configuration.daemon_name}"
84
+ exit
85
+ end
86
+
87
+ def initialize( configuration )
88
+ @configuration = configuration
89
+ end
90
+
91
+ def before_daemonize
92
+ DaemonKit.configuration = @configuration
93
+
94
+ set_load_path
95
+ load_gems
96
+ load_patches
97
+ load_environment
98
+ load_predaemonize_configs
99
+ end
100
+
101
+ def after_daemonize
102
+ set_umask
103
+
104
+ initialize_logger
105
+ initialize_signal_traps
106
+
107
+ include_core_lib
108
+ load_postdaemonize_configs
109
+ configure_backtraces
110
+
111
+ set_process_name
112
+
113
+ DaemonKit.logger.info( "DaemonKit (#{DaemonKit::VERSION}) booted, now running #{DaemonKit.configuration.daemon_name}" )
114
+
115
+ if DaemonKit.configuration.user || DaemonKit.configuration.group
116
+ euid = Process.euid
117
+ egid = Process.egid
118
+ uid = Process.uid
119
+ gid = Process.gid
120
+ DaemonKit.logger.info( "DaemonKit dropped privileges to: #{euid} (EUID), #{egid} (EGID), #{uid} (UID), #{gid} (GID)" )
121
+ end
122
+ end
123
+
124
+ def set_load_path
125
+ configuration.load_paths.each do |d|
126
+ $:.unshift( "#{DAEMON_ROOT}/#{d}" ) if File.directory?( "#{DAEMON_ROOT}/#{d}" )
127
+ end
128
+ end
129
+
130
+ def load_gems
131
+
132
+ end
133
+
134
+ def load_patches
135
+
136
+ end
137
+
138
+ def load_environment
139
+ return if @environment_loaded
140
+ @environment_loaded = true
141
+
142
+ config = configuration
143
+
144
+ eval(IO.read(configuration.environment_path), binding, configuration.environment_path)
145
+
146
+ eval(IO.read(configuration.daemon_initializer), binding, configuration.daemon_initializer) if File.exist?( configuration.daemon_initializer )
147
+ end
148
+
149
+ def load_predaemonize_configs
150
+ Dir[ File.join( DAEMON_ROOT, 'config', 'pre-daemonize', '*.rb' ) ].each do |f|
151
+ next if File.basename( f ) == File.basename( configuration.daemon_initializer )
152
+
153
+ require f
154
+ end
155
+ end
156
+
157
+ def load_postdaemonize_configs
158
+ Dir[ File.join( DAEMON_ROOT, 'config', 'post-daemonize', '*.rb' ) ].each do |f|
159
+ require f
160
+ end
161
+ end
162
+
163
+ def set_umask
164
+ File.umask configuration.umask
165
+ end
166
+
167
+ def initialize_logger
168
+ return if DaemonKit.logger
169
+
170
+ unless logger = configuration.logger
171
+ logger = AbstractLogger.new( configuration.log_path )
172
+ logger.level = configuration.log_level
173
+ logger.copy_to_stdout = configuration.log_stdout
174
+ end
175
+
176
+ DaemonKit.logger = logger
177
+
178
+ DaemonKit.logger.info "DaemonKit (#{DaemonKit::VERSION}) booting in #{DAEMON_ENV} mode"
179
+
180
+ configuration.trap("USR1") {
181
+ DaemonKit.logger.level = DaemonKit.logger.debug? ? :info : :debug
182
+ DaemonKit.logger.info "Log level changed to #{DaemonKit.logger.debug? ? 'DEBUG' : 'INFO' }"
183
+ }
184
+ configuration.trap("USR2") {
185
+ DaemonKit.logger.level = :debug
186
+ DaemonKit.logger.info "Log level changed to DEBUG"
187
+ }
188
+ configuration.trap("HUP") {
189
+ DaemonKit.logger.close
190
+ }
191
+ end
192
+
193
+ def initialize_signal_traps
194
+ term_proc = Proc.new { DaemonKit::Initializer.shutdown( true ) }
195
+ configuration.trap( 'INT', term_proc )
196
+ configuration.trap( 'TERM', term_proc )
197
+ at_exit { DaemonKit::Initializer.shutdown }
198
+ end
199
+
200
+ def include_core_lib
201
+ if File.exists?( core_lib = File.join( DAEMON_ROOT, 'lib', configuration.daemon_name + '.rb' ) )
202
+ require core_lib
203
+ end
204
+ end
205
+
206
+ def configure_backtraces
207
+ Thread.abort_on_exception = configuration.backtraces
208
+ end
209
+
210
+ def set_process_name
211
+ $0 = configuration.daemon_name
212
+ end
213
+
214
+ def self.log_exceptions
215
+ trace_file = File.join( DaemonKit.root, "backtrace-#{Time.now.strftime('%Y%m%d%H%M%S')}-#{Process.pid}.log" )
216
+ trace_log = Logger.new( trace_file )
217
+
218
+ # Find the last exception
219
+ e = nil
220
+ ObjectSpace.each_object {|o|
221
+ if ::Exception === o
222
+ e = o
223
+ end
224
+ }
225
+
226
+ trace_log.info "*** Below you'll find the most recent exception thrown, this will likely (but not certainly) be the exception that made #{DaemonKit.configuration.daemon_name} exit abnormally ***"
227
+ trace_log.error e
228
+
229
+ trace_log.info "*** Below you'll find all the exception objects in memory, some of them may have been thrown in your application, others may just be in memory because they are standard exceptions ***"
230
+ ObjectSpace.each_object {|o|
231
+ if ::Exception === o
232
+ trace_log.error o
233
+ end
234
+ }
235
+
236
+ trace_log.close
237
+ end
238
+ end
239
+
240
+ # Holds our various configuration values
241
+ class Configuration
242
+
243
+ include Configurable
244
+
245
+ # Root to the daemon
246
+ attr_reader :root_path
247
+
248
+ # List of load paths
249
+ attr_accessor :load_paths
250
+
251
+ # Custom logger instance to use
252
+ attr_accessor :logger
253
+
254
+ # The log level to use, defaults to DEBUG
255
+ attr_accessor :log_level
256
+
257
+ # Path to the log file, defaults to 'log/<environment>.log'
258
+ configurable :log_path
259
+
260
+ # Duplicate log data to stdout
261
+ attr_accessor :log_stdout
262
+
263
+ # Path to the pid file, defaults to 'log/<daemon_name>.pid'
264
+ attr_accessor :pid_file
265
+
266
+ # The application name
267
+ configurable :daemon_name, :locked => true
268
+
269
+ # Use the force kill patch? Give the number of seconds
270
+ configurable :force_kill_wait
271
+
272
+ # Should be log backtraces
273
+ configurable :backtraces, false
274
+
275
+ # Configurable umask
276
+ configurable :umask, 0022
277
+
278
+ # Configurable user
279
+ configurable :user, :locked => true
280
+
281
+ # Confgiruable group
282
+ configurable :group, :locked => true
283
+
284
+ # Collection of signal traps
285
+ attr_reader :signal_traps
286
+
287
+ # Our safety net (#Safety) instance
288
+ attr_accessor :safety_net
289
+
290
+ # :nodoc: Shutdown hooks
291
+ attr_reader :shutdown_hooks
292
+
293
+ def initialize
294
+ parse_arguments!
295
+
296
+ set_root_path!
297
+ set_daemon_defaults!
298
+
299
+ self.load_paths = default_load_paths
300
+ self.log_level ||= default_log_level
301
+ self.log_path ||= default_log_path
302
+
303
+ self.force_kill_wait = false
304
+
305
+ self.safety_net = DaemonKit::Safety.instance
306
+
307
+ @signal_traps = {}
308
+ @shutdown_hooks = []
309
+ end
310
+
311
+ def environment
312
+ ::DAEMON_ENV
313
+ end
314
+
315
+ # The path to the current environment's file (<tt>development.rb</tt>, etc.). By
316
+ # default the file is at <tt>config/environments/#{environment}.rb</tt>.
317
+ def environment_path
318
+ "#{root_path}/config/environments/#{environment}.rb"
319
+ end
320
+
321
+ def daemon_initializer
322
+ "#{root_path}/config/initializers/#{self.daemon_name}.rb"
323
+ end
324
+
325
+ # Add a trap for the specified signal, can be code block or a proc
326
+ def trap( signal, proc = nil, &block )
327
+ return if proc.nil? && !block_given?
328
+
329
+ unless @signal_traps.has_key?( signal )
330
+ set_trap( signal )
331
+ end
332
+
333
+ @signal_traps[signal].unshift( proc || block )
334
+ end
335
+
336
+ # Add a block or proc to be called during shutdown
337
+ def at_shutdown( proc = nil, &block )
338
+ return if proc.nil? && !block_given?
339
+
340
+ @shutdown_hooks << ( proc || block )
341
+ end
342
+
343
+ def pid_file
344
+ @pid_file ||= "#{File.dirname(self.log_path)}/#{self.daemon_name}.pid"
345
+ end
346
+
347
+ protected
348
+
349
+ def run_traps( signal )
350
+ DaemonKit.logger.info "Running signal traps for #{signal}"
351
+ self.signal_traps[ signal ].each { |trap| trap.call }
352
+ end
353
+
354
+ private
355
+
356
+ def set_trap( signal )
357
+ DaemonKit.logger.info "Setting up trap for #{signal}"
358
+ @signal_traps[ signal ] = []
359
+ Signal.trap( signal, Proc.new { self.run_traps( signal ) } )
360
+ end
361
+
362
+ def parse_arguments!
363
+ return unless own_args?
364
+
365
+ configs = Arguments.configuration( ARGV ).first
366
+ @unused_arguments = {}
367
+
368
+ configs.each do |c|
369
+ k,v = c.split('=')
370
+
371
+ if v.nil?
372
+ error( "#{k} has no value" )
373
+ next
374
+ end
375
+
376
+ begin
377
+ if self.respond_to?( k )
378
+ self.send( "#{k}=", v ) # pid_file = /var/run/foo.pid
379
+ else
380
+ @unused_arguments[ k ] = v
381
+ end
382
+ rescue => e
383
+ error( "Couldn't set `#{k}' to `#{v}': #{e.message}" )
384
+ end
385
+ end
386
+ end
387
+
388
+ # DANGEROUS: Change the value of DAEMON_ENV
389
+ def environment=( env )
390
+ ::DAEMON_ENV.replace( env )
391
+ end
392
+
393
+ def set_root_path!
394
+ raise "DAEMON_ROOT is not set" unless defined?(::DAEMON_ROOT)
395
+ raise "DAEMON_ROOT is not a directory" unless File.directory?(::DAEMON_ROOT)
396
+
397
+ @root_path = ::DAEMON_ROOT.to_absolute_path
398
+
399
+ Object.const_set(:RELATIVE_DAEMON_ROOT, ::DAEMON_ROOT.dup) unless defined?(::RELATIVE_DAEMON_ROOT)
400
+ ::DAEMON_ROOT.replace @root_path
401
+ end
402
+
403
+ def set_daemon_defaults!
404
+ self.log_stdout = false
405
+ end
406
+
407
+ def default_load_paths
408
+ [ 'lib' ]
409
+ end
410
+
411
+ def default_log_path
412
+ File.join(root_path, 'log', "#{environment}.log")
413
+ end
414
+
415
+ def default_log_level
416
+ environment == 'production' ? :info : :debug
417
+ end
418
+
419
+ def error( msg )
420
+ msg = "[E] Configuration: #{msg}"
421
+
422
+ if DaemonKit.logger
423
+ DaemonKit.logger.error( msg )
424
+ else
425
+ STDERR.puts msg
426
+ end
427
+ end
428
+
429
+ # If we are executed with any of these commands, don't allow
430
+ # arguments to be parsed cause they will interfere with the
431
+ # script encapsulating DaemonKit, like capistrano
432
+ def own_args?
433
+ ![ 'cap' ].include?( File.basename( $0 ) )
434
+ end
435
+ end
436
+
437
+
438
+ end