Module: God
- Defined in:
- lib/god.rb,
lib/god/task.rb,
lib/god/watch.rb,
lib/god/driver.rb,
lib/god/errors.rb,
lib/god/logger.rb,
lib/god/metric.rb,
lib/god/socket.rb,
lib/god/cli/run.rb,
lib/god/contact.rb,
lib/god/process.rb,
lib/god/trigger.rb,
lib/god/behavior.rb,
lib/god/registry.rb,
lib/god/timeline.rb,
lib/god/condition.rb,
lib/god/cli/command.rb,
lib/god/cli/version.rb,
lib/god/configurable.rb,
lib/god/event_handler.rb,
lib/god/simple_logger.rb,
lib/god/contacts/email.rb,
lib/god/contacts/prowl.rb,
lib/god/contacts/scout.rb,
lib/god/contacts/sensu.rb,
lib/god/contacts/slack.rb,
lib/god/system/process.rb,
lib/god/contacts/jabber.rb,
lib/god/contacts/statsd.rb,
lib/god/conditions/tries.rb,
lib/god/contacts/hipchat.rb,
lib/god/contacts/twitter.rb,
lib/god/contacts/webhook.rb,
lib/god/conditions/always.rb,
lib/god/conditions/lambda.rb,
lib/god/contacts/airbrake.rb,
lib/god/contacts/campfire.rb,
lib/god/conditions/complex.rb,
lib/god/conditions/flapping.rb,
lib/god/conditions/cpu_usage.rb,
lib/god/conditions/disk_usage.rb,
lib/god/conditions/file_mtime.rb,
lib/god/system/portable_poller.rb,
lib/god/conditions/file_touched.rb,
lib/god/conditions/memory_usage.rb,
lib/god/behaviors/clean_pid_file.rb,
lib/god/conditions/process_exits.rb,
lib/god/system/slash_proc_poller.rb,
lib/god/conditions/process_running.rb,
lib/god/behaviors/clean_unix_socket.rb,
lib/god/conditions/degrading_lambda.rb,
lib/god/conditions/socket_responding.rb,
lib/god/event_handlers/dummy_handler.rb,
lib/god/conditions/http_response_code.rb,
lib/god/event_handlers/kqueue_handler.rb,
lib/god/behaviors/notify_when_flapping.rb,
lib/god/event_handlers/netlink_handler.rb
Defined Under Namespace
Modules: Behaviors, CLI, Conditions, Configurable, Contacts, System Classes: AbstractMethodNotOverriddenError, Behavior, Condition, Contact, Driver, DriverEvent, DriverEventQueue, DriverOperation, DummyHandler, EventCondition, EventHandler, EventRegistrationFailedError, InvalidCommandError, KQueueHandler, Logger, Metric, NetlinkHandler, NoSuchBehaviorError, NoSuchConditionError, NoSuchContactError, NoSuchWatchError, PollCondition, Process, Registry, SimpleLogger, Socket, Task, TimedEvent, Timeline, Trigger, TriggerCondition, Watch
Constant Summary collapse
- VERSION =
The String version number for this package.
'0.13.7'
- LOG_BUFFER_SIZE_DEFAULT =
The Integer number of lines of backlog to keep for the logger.
100
- PID_FILE_DIRECTORY_DEFAULTS =
An Array of directory paths to be used as the default PID file directory. This list will be searched in order and the first one that has write permissions will be used.
['/var/run/god', '~/.god/pids']
- DRB_PORT_DEFAULT =
The default Integer port number for the DRb communcations channel.
17165
- DRB_ALLOW_DEFAULT =
The default Array of String IPs that will allow DRb communication access.
['127.0.0.1']
- LOG_LEVEL_DEFAULT =
The default Symbol log level.
:info
- TERMINATE_TIMEOUT_DEFAULT =
The default Integer number of seconds to wait for god to terminate when issued the quit command.
10
- STOP_TIMEOUT_DEFAULT =
The default Integer number of seconds to wait for a process to terminate.
10
- STOP_SIGNAL_DEFAULT =
The default String signal to send for the stop command.
'TERM'
Class Attribute Summary collapse
-
.contact_groups ⇒ Object
internal.
-
.contacts ⇒ Object
internal.
-
.groups ⇒ Object
internal.
-
.inited ⇒ Object
internal.
-
.main ⇒ Object
internal.
-
.pending_watch_states ⇒ Object
internal.
-
.pending_watches ⇒ Object
internal.
-
.running ⇒ Object
internal.
-
.server ⇒ Object
internal.
-
.watches ⇒ Object
internal.
Class Method Summary collapse
-
.at_exit ⇒ Object
To be called on program exit to start god.
-
.contact(kind) {|c| ... } ⇒ Object
Instantiate a new Contact of the given kind and send it to the block.
-
.control(name, command) ⇒ Object
Control the lifecycle of the given task(s).
-
.internal_init ⇒ Object
Initialize internal data.
-
.join ⇒ Object
Prevent god from exiting.
-
.load(glob) ⇒ Object
Load the given file(s) according to the given glob.
-
.pattern_match(pattern, list) ⇒ Object
Match a shortened pattern against a list of String candidates.
- .registry ⇒ Object
-
.running_load(code, filename, action = nil) ⇒ Object
Load a config file into a running god instance.
-
.running_log(watch_name, since) ⇒ Object
Log lines for the given task since the specified time.
-
.setup ⇒ Object
Setup pid file directory and log system.
-
.signal(name, signal) ⇒ Object
Send a signal to each task.
-
.start ⇒ Object
Initialize and startup the machinery that makes god work.
-
.status ⇒ Object
Gather the status of each task.
-
.stop_all ⇒ Object
Unmonitor and stop all tasks.
-
.task(klass = Task) {|t| ... } ⇒ Object
Instantiate a new, empty Task object and yield it to the mandatory block.
-
.terminate ⇒ Object
Force the termination of god.
-
.uncontact(contact) ⇒ Object
Remove the given contact from god.
-
.unwatch(watch) ⇒ Object
Unmonitor and remove the given watch from god.
-
.version ⇒ Object
Returns the version String.
-
.watch(&block) ⇒ Object
Instantiate a new, empty Watch object and pass it to the mandatory block.
- .watches_by_name(name) ⇒ Object
Class Attribute Details
.contact_groups ⇒ Object
internal
210 211 212 |
# File 'lib/god.rb', line 210 def contact_groups @contact_groups end |
.contacts ⇒ Object
internal
210 211 212 |
# File 'lib/god.rb', line 210 def contacts @contacts end |
.groups ⇒ Object
internal
210 211 212 |
# File 'lib/god.rb', line 210 def groups @groups end |
.inited ⇒ Object
internal
210 211 212 |
# File 'lib/god.rb', line 210 def inited @inited end |
.main ⇒ Object
internal
210 211 212 |
# File 'lib/god.rb', line 210 def main @main end |
.pending_watch_states ⇒ Object
internal
210 211 212 |
# File 'lib/god.rb', line 210 def pending_watch_states @pending_watch_states end |
.pending_watches ⇒ Object
internal
210 211 212 |
# File 'lib/god.rb', line 210 def pending_watches @pending_watches end |
.running ⇒ Object
internal
210 211 212 |
# File 'lib/god.rb', line 210 def running @running end |
.server ⇒ Object
internal
210 211 212 |
# File 'lib/god.rb', line 210 def server @server end |
.watches ⇒ Object
internal
210 211 212 |
# File 'lib/god.rb', line 210 def watches @watches end |
Class Method Details
.at_exit ⇒ Object
To be called on program exit to start god.
Returns nothing.
738 739 740 741 |
# File 'lib/god.rb', line 738 def self.at_exit self.start self.join end |
.contact(kind) {|c| ... } ⇒ Object
Instantiate a new Contact of the given kind and send it to the block. Then prepare, validate, and record the Contact. Aborts on invalid kind, duplicate contact name, invalid contact, or conflicting group name.
kind - The Symbol contact class specifier.
Returns nothing.
373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 |
# File 'lib/god.rb', line 373 def self.contact(kind) # Ensure internal init has run. self.internal_init # Verify contact has been loaded. if CONTACT_LOAD_SUCCESS[kind] == false applog(nil, :error, "A required dependency for the #{kind} contact is unavailable.") applog(nil, :error, "Run the following commands to install the dependencies:") CONTACT_DEPS[kind].each do |d| applog(nil, :error, " [sudo] gem install #{d}") end abort end # Create the contact. begin c = Contact.generate(kind) rescue NoSuchContactError => e abort e. end # Send to block so config can set attributes. yield(c) if block_given? # Call prepare on the contact. c.prepare # Remove existing contacts of same name. existing_contact = self.contacts[c.name] if self.running && existing_contact self.uncontact(existing_contact) end # Warn and noop if the contact has been defined before. if self.contacts[c.name] || self.contact_groups[c.name] applog(nil, :warn, "Contact name '#{c.name}' already used for a Contact or Contact Group") return end # Abort if the Contact is invalid, the Contact will have printed out its # own error messages by now. unless Contact.valid?(c) && c.valid? abort "Exiting on invalid contact" end # Add to list of contacts. self.contacts[c.name] = c # Add to contact group if specified. if c.group # Ensure group name hasn't been used for a contact already. if self.contacts[c.group] abort "Contact Group name '#{c.group}' already used for a Contact" end self.contact_groups[c.group] ||= [] self.contact_groups[c.group] << c end end |
.control(name, command) ⇒ Object
Control the lifecycle of the given task(s).
name - The String name of a task/group. If empty, invokes command for all tasks. command - The String command to run. Valid commands are:
"start", "monitor", "restart", "stop", "unmonitor", "remove".
Returns an Array of String task names affected by the command.
459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 |
# File 'lib/god.rb', line 459 def self.control(name, command) # Get the list of items. items = self.watches_by_name(name) jobs = [] # Do the command. case command when "start", "monitor" items.each { |w| jobs << Thread.new { w.monitor if w.state != :up } } when "restart" items.each { |w| jobs << Thread.new { w.move(:restart) } } when "stop" items.each { |w| jobs << Thread.new { w.action(:stop); w.unmonitor if w.state != :unmonitored } } when "unmonitor" items.each { |w| jobs << Thread.new { w.unmonitor if w.state != :unmonitored } } when "remove" items.each { |w| self.unwatch(w) } else raise InvalidCommandError.new end jobs.each { |j| j.join } items.map { |x| x.name } end |
.internal_init ⇒ Object
Initialize internal data.
Returns nothing.
238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/god.rb', line 238 def self.internal_init # Only do this once. return if self.inited # Variable init. self.watches = {} self.groups = {} self.pending_watches = [] self.pending_watch_states = {} self.contacts = {} self.contact_groups = {} # Set defaults. self.log_buffer_size ||= LOG_BUFFER_SIZE_DEFAULT self.port ||= DRB_PORT_DEFAULT self.allow ||= DRB_ALLOW_DEFAULT self.log_level ||= LOG_LEVEL_DEFAULT self.terminate_timeout ||= TERMINATE_TIMEOUT_DEFAULT # Additional setup. self.setup # Log level. log_level_map = {:debug => Logger::DEBUG, :info => Logger::INFO, :warn => Logger::WARN, :error => Logger::ERROR, :fatal => Logger::FATAL} LOG.level = log_level_map[self.log_level] # Init has been executed. self.inited = true # Not yet running. self.running = false end |
.join ⇒ Object
Prevent god from exiting.
Returns nothing.
726 727 728 |
# File 'lib/god.rb', line 726 def self.join self.main.join if self.main end |
.load(glob) ⇒ Object
Load the given file(s) according to the given glob.
glob - The glob-enabled String path to load.
Returns nothing.
644 645 646 647 648 |
# File 'lib/god.rb', line 644 def self.load(glob) Dir[glob].each do |f| Kernel.load f end end |
.pattern_match(pattern, list) ⇒ Object
Match a shortened pattern against a list of String candidates. The pattern is expanded into a regular expression by inserting .* between each character.
pattern - The String containing the abbreviation. list - The Array of Strings to match against.
Examples
list = %w{ foo bar bars }
pattern = 'br'
God.pattern_match(list, pattern)
# => ['bar', 'bars']
Returns the Array of matching name Strings.
760 761 762 763 764 765 766 |
# File 'lib/god.rb', line 760 def self.pattern_match(pattern, list) regex = pattern.split('').join('.*') list.select do |item| item =~ Regexp.new(regex) end.sort_by { |x| x.size } end |
.registry ⇒ Object
2 3 4 |
# File 'lib/god/registry.rb', line 2 def self.registry @registry ||= Registry.new end |
.running_load(code, filename, action = nil) ⇒ Object
Load a config file into a running god instance. Rescues any exceptions that the config may raise and reports these back to the caller.
code - The String config file contents. filename - The filename of the config file. action - The optional String command specifying how to deal with
existing watches. Valid options are: 'stop', 'remove' or
'leave' (default).
Returns a three-tuple Array [loaded_names, errors, unloaded_names] where:
loaded_names - The Array of String task names that were loaded.
errors - The String of error messages produced during the
load phase. Will be a blank String if no errors
were encountered.
unloaded_names - The Array of String task names that were unloaded
from the system (if 'remove' or 'stop' was
specified as the action).
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 |
# File 'lib/god.rb', line 583 def self.running_load(code, filename, action = nil) errors = "" loaded_watches = [] unloaded_watches = [] jobs = [] begin LOG.start_capture Gem.clear_paths eval(code, root_binding, filename) self.pending_watches.each do |w| if previous_state = self.pending_watch_states[w.name] w.monitor unless previous_state == :unmonitored else w.monitor if w.autostart? end end loaded_watches = self.pending_watches.map { |w| w.name } self.pending_watches.clear self.pending_watch_states.clear self.watches.each do |name, watch| next if loaded_watches.include?(name) case action when 'stop' jobs << Thread.new(watch) { |w| w.action(:stop); self.unwatch(w) } unloaded_watches << name when 'remove' jobs << Thread.new(watch) { |w| self.unwatch(w) } unloaded_watches << name when 'leave', '', nil # Do nothing else raise InvalidCommandError, "Unknown action: #{action}" end end # Make sure we quit capturing when we're done. LOG.finish_capture rescue Exception => e # Don't ever let running_load take down god. errors << LOG.finish_capture unless e.instance_of?(SystemExit) errors << e. << "\n" errors << e.backtrace.join("\n") end end jobs.each { |t| t.join } [loaded_watches, errors, unloaded_watches] end |
.running_log(watch_name, since) ⇒ Object
Log lines for the given task since the specified time.
watch_name - The String name of the task (may be abbreviated). since - The Time since which to report log lines.
Raises God::NoSuchWatchError if no tasks matched. Returns the String of newline separated log lines.
556 557 558 559 560 561 562 563 564 |
# File 'lib/god.rb', line 556 def self.running_log(watch_name, since) matches = pattern_match(watch_name, self.watches.keys) unless matches.first raise NoSuchWatchError.new end LOG.watch_log_since(matches.first, since) end |
.setup ⇒ Object
Setup pid file directory and log system.
Returns nothing.
653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 |
# File 'lib/god.rb', line 653 def self.setup if self.pid_file_directory # Pid file dir was specified, ensure it is created and writable. unless File.exist?(self.pid_file_directory) begin FileUtils.mkdir_p(self.pid_file_directory) rescue Errno::EACCES => e abort "Failed to create pid file directory: #{e.}" end end unless File.writable?(self.pid_file_directory) abort "The pid file directory (#{self.pid_file_directory}) is not writable by #{Etc.getlogin}" end else # No pid file dir specified, try defaults. PID_FILE_DIRECTORY_DEFAULTS.each do |idir| dir = File.(idir) begin FileUtils.mkdir_p(dir) if File.writable?(dir) self.pid_file_directory = dir break end rescue Errno::EACCES => e end end unless self.pid_file_directory dirs = PID_FILE_DIRECTORY_DEFAULTS.map { |x| File.(x) } abort "No pid file directory exists, could be created, or is writable at any of #{dirs.join(', ')}" end end if God::Logger.syslog LOG.info("Syslog enabled.") else LOG.info("Syslog disabled.") end applog(nil, :info, "Using pid file directory: #{self.pid_file_directory}") end |
.signal(name, signal) ⇒ Object
Send a signal to each task.
name - The String name of the task or group. signal - The String or integer signal to send. e.g. ‘HUP’, 9.
Returns an Array of String names of the tasks affected.
541 542 543 544 545 546 547 |
# File 'lib/god.rb', line 541 def self.signal(name, signal) items = watches_by_name(name) jobs = [] items.each { |w| jobs << Thread.new { w.signal(signal) } } jobs.each { |j| j.join } items.map { |x| x.name } end |
.start ⇒ Object
Initialize and startup the machinery that makes god work.
Returns nothing.
699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 |
# File 'lib/god.rb', line 699 def self.start self.internal_init # Instantiate server. self.server = Socket.new(self.port, self.socket_user, self.socket_group, self.socket_perms) # Start monitoring any watches set to autostart. self.watches.values.each { |w| w.monitor if w.autostart? } # Clear pending watches. self.pending_watches.clear # Mark as running. self.running = true # Don't exit. self.main = Thread.new do loop do sleep 60 end end end |
.status ⇒ Object
Gather the status of each task.
Examples
God.status
# => { 'mongrel' => :up, 'nginx' => :up }
Returns a Hash where the key is the String task name and the value is the
Symbol status.
527 528 529 530 531 532 533 |
# File 'lib/god.rb', line 527 def self.status info = {} self.watches.map do |name, w| info[name] = {:state => w.state, :group => w.group} end info end |
.stop_all ⇒ Object
Unmonitor and stop all tasks.
Returns true on success, false if all tasks could not be stopped within 10 seconds
490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 |
# File 'lib/god.rb', line 490 def self.stop_all self.watches.sort.each do |name, w| Thread.new do w.action(:stop) w.unmonitor if w.state != :unmonitored end end terminate_timeout.times do return true unless self.watches.map { |name, w| w.alive? }.any? sleep 1 end return false end |
.task(klass = Task) {|t| ... } ⇒ Object
Instantiate a new, empty Task object and yield it to the mandatory block. The attributes of the task will be set by the configuration file. Aborts on duplicate task name, invalid task, or conflicting group name.
Returns nothing.
289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/god.rb', line 289 def self.task(klass = Task) # Ensure internal init has run. self.internal_init t = klass.new yield(t) # Do the post-configuration. t.prepare # If running, completely remove the watch (if necessary) to prepare for # the reload existing_watch = self.watches[t.name] if self.running && existing_watch self.pending_watch_states[existing_watch.name] = existing_watch.state self.unwatch(existing_watch) end # Ensure the new watch has a unique name. if self.watches[t.name] || self.groups[t.name] abort "Task name '#{t.name}' already used for a Task or Group" end # Ensure watch is internally valid. t.valid? || abort("Task '#{t.name}' is not valid (see above)") # Add to list of watches. self.watches[t.name] = t # Add to pending watches. self.pending_watches << t # Add to group if specified. if t.group # Ensure group name hasn't been used for a watch already. if self.watches[t.group] abort "Group name '#{t.group}' already used for a Task" end self.groups[t.group] ||= [] self.groups[t.group] << t end # Register watch. t.register! # Log. if self.running && existing_watch applog(t, :info, "#{t.name} Reloaded config") elsif self.running applog(t, :info, "#{t.name} Loaded config") end end |
.terminate ⇒ Object
Force the termination of god.
-
Clean up pid file if one exists
-
Stop DRb service
-
Hard exit using exit!
Never returns because the process will no longer exist!
512 513 514 515 516 |
# File 'lib/god.rb', line 512 def self.terminate FileUtils.rm_f(self.pid) if self.pid self.server.stop if self.server exit!(0) end |
.uncontact(contact) ⇒ Object
Remove the given contact from god.
contact - The Contact to remove.
Returns nothing.
438 439 440 441 442 443 |
# File 'lib/god.rb', line 438 def self.uncontact(contact) self.contacts.delete(contact.name) if contact.group self.contact_groups[contact.group].delete(contact) end end |
.unwatch(watch) ⇒ Object
Unmonitor and remove the given watch from god.
watch - The Watch to remove.
Returns nothing.
348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 |
# File 'lib/god.rb', line 348 def self.unwatch(watch) # Unmonitor. watch.unmonitor unless watch.state == :unmonitored # Unregister. watch.unregister! # Remove from watches. self.watches.delete(watch.name) # Remove from groups. if watch.group self.groups[watch.group].delete(watch) end applog(watch, :info, "#{watch.name} unwatched") end |
.version ⇒ Object
Returns the version String.
731 732 733 |
# File 'lib/god.rb', line 731 def self.version God::VERSION end |
.watch(&block) ⇒ Object
Instantiate a new, empty Watch object and pass it to the mandatory block. The attributes of the watch will be set by the configuration file. Aborts on duplicate watch name, invalid watch, or conflicting group name.
Returns nothing.
280 281 282 |
# File 'lib/god.rb', line 280 def self.watch(&block) self.task(Watch, &block) end |
.watches_by_name(name) ⇒ Object
445 446 447 448 449 450 |
# File 'lib/god.rb', line 445 def self.watches_by_name(name) case name when "", nil then self.watches.values.dup else Array(self.watches[name] || self.groups[name]).dup end end |