hive 0.1.8

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 (3) hide show
  1. data/lib/hive/scheduler.rb +77 -0
  2. data/lib/hive/worker.rb +114 -0
  3. metadata +63 -0
@@ -0,0 +1,77 @@
1
+ require 'rubygems'
2
+ require 'facets/duration' unless 1.respond_to? :minute
3
+
4
+ require 'hive/worker'
5
+
6
+ module Hive
7
+
8
+ class Scheduler < Hive::Worker
9
+
10
+ def stop_tasks
11
+ threads = Thread.list.select { |t| t.alive? && t != Thread.current }
12
+ until threads.empty?
13
+ logger.info "#{threads.size} threads still running ... "
14
+ threads.each { |t| t.kill && t != Thread.current }
15
+ threads = threads.select { |t| t.alive? }
16
+ end
17
+ logger.info "All threads are finished."
18
+ end
19
+
20
+ private
21
+
22
+ def schedule( method, options )
23
+ raise ArgumentError.new( "Invalid schedule for task #{method}.") unless valid?(options)
24
+ logger.info "Scheduling task #{method} ..."
25
+ Thread.new do
26
+ t = Time.now
27
+ loop do
28
+ t += 60
29
+ # the rescue handles the unusual case where t - Time.now is negative
30
+ sleep( ( options[:interval] || ( t - Time.now ) ).to_i ) rescue nil
31
+ if match( t, options )
32
+ if self.respond_to?( method )
33
+ Thread.new do
34
+ logger.info "Running task #{method} ..."
35
+ begin
36
+ self.send( method )
37
+ rescue Exception => e
38
+ logger.error e
39
+ end
40
+ logger.info "Task #{method} complete."
41
+ end
42
+ else
43
+ logger.warn "Task #{method} scheduled but not defined."
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+
50
+ def valid?( options )
51
+ ! ( options.keys & [ :minute, :hour, :day, :weekday, :month, :interval] ).empty?
52
+ end
53
+
54
+ def match( t, options )
55
+ options[:interval] ||
56
+ (( match_item( options[:minute], t.min )) &&
57
+ ( match_item( options[:hour], t.hour )) &&
58
+ ( match_item( options[:day], t.day )) &&
59
+ ( match_item( options[:weekday], t.wday )) &&
60
+ ( match_item( options[:month], t.month )))
61
+ end
62
+
63
+ def match_item( x, y )
64
+ case x
65
+ when nil then true
66
+ when Array then x.include? y
67
+ when Range then x.include? y
68
+ when Integer then x == y
69
+ else
70
+ logger.warn "Value #{x.inspect} will never be matched"
71
+ false
72
+ end
73
+ end
74
+
75
+ end
76
+
77
+ end
@@ -0,0 +1,114 @@
1
+ module Kernel
2
+ def safe_trap(*signals)
3
+ signals.each { |s| trap(s) { yield } }
4
+ Thread.new { loop { sleep 1 } } if RUBY_PLATFORM =~ /mswin32/
5
+ end
6
+ end
7
+
8
+ module Hive
9
+
10
+ # "Workers" are just dedicated processes. Managers, Servers, and Monitors are all
11
+ # examples of Workers. This class just encapsulates the common features across all
12
+ # Workers: daemonization, signal traps, console support, logging, only-ness, etc.
13
+
14
+ class Worker
15
+
16
+ def self.run( options = {} )
17
+ @instance ||= new( options )
18
+ @instance.start
19
+ end
20
+
21
+ # make this the one-and-only
22
+ def self.instance ; @instance ; end
23
+ class << self ; private :new, :allocate ; end
24
+ private :dup, :clone
25
+
26
+ attr_accessor :logger, :options
27
+
28
+ def initialize( options )
29
+ @options = options
30
+ end
31
+
32
+ # returns the PID of the new process
33
+ def start
34
+ pid = daemonize if options[ :daemon ]
35
+ puts "#{self.class.name} process #{pid} started ..." if pid
36
+ return pid if pid
37
+ begin
38
+ # from here on in, we're in the daemon
39
+ start_logger ; logger.info "#{self.class} starting ..."
40
+ start_debugger if options[:debug] # unless Kernel.engine == 'jruby'
41
+ # various ways to talk to a worker
42
+ set_traps ; start_console ; start_drb
43
+ start_tasks.join
44
+ rescue Exception => e
45
+ logger.error e.to_s rescue nil
46
+ end
47
+ end
48
+
49
+ def stop
50
+ logger.info "#{self.class} shutting down ..."
51
+ @console.stop if @console
52
+ stop_tasks
53
+ end
54
+
55
+ def restart ; stop ; start ; end
56
+
57
+ def daemonize
58
+ pwd = Dir.pwd ; pid = fork ; return pid if pid ; Dir.chdir( pwd )
59
+ # Make sure all file descriptors are closed
60
+ ObjectSpace.each_object( IO ) do | io |
61
+ unless [ STDIN, STDOUT, STDERR ].include?(io)
62
+ begin
63
+ unless io.closed?
64
+ io.close
65
+ end
66
+ rescue ::Exception
67
+ end
68
+ end
69
+ end
70
+ File.umask 0000 ; STDIN.reopen( '/dev/null') ;
71
+ STDOUT.reopen( '/dev/null', 'a' ) ; STDERR.reopen( STDOUT )
72
+ nil # return nil for child process, just like fork does
73
+ end
74
+
75
+ def set_traps
76
+ safe_trap( 'HUP' ) { restart }
77
+ safe_trap( 'TERM','INT' ) { stop }
78
+ end
79
+
80
+ def start_console
81
+ # TODO: add live console support
82
+ end
83
+
84
+ def start_drb
85
+ # TODO: add DRb support
86
+ end
87
+
88
+ def start_debugger
89
+ require 'ruby-debug' ; Debugger.start
90
+ Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
91
+ logger.info "ruby-debug enabled"
92
+ end
93
+
94
+ def start_logger
95
+ if options[ :logger ]
96
+ @logger = options[ :logger ]
97
+ else
98
+ require 'logger'
99
+ @logger = Logger.new( 'log.out' )
100
+ end
101
+ end
102
+
103
+ protected
104
+
105
+ # workers should override these methods
106
+ def start_tasks
107
+ end
108
+
109
+ def stop_tasks
110
+ end
111
+
112
+ end
113
+
114
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: hive
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.8
5
+ platform: ruby
6
+ authors:
7
+ - Dan Yoder
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-08-30 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: facets
17
+ type: :runtime
18
+ version_requirement:
19
+ version_requirements: !ruby/object:Gem::Requirement
20
+ requirements:
21
+ - - ">="
22
+ - !ruby/object:Gem::Version
23
+ version: "1.0"
24
+ version:
25
+ description:
26
+ email: dan@zeraweb.com
27
+ executables: []
28
+
29
+ extensions: []
30
+
31
+ extra_rdoc_files: []
32
+
33
+ files:
34
+ - lib/hive/scheduler.rb
35
+ - lib/hive/worker.rb
36
+ has_rdoc: true
37
+ homepage: http://github.com/dyoder/hive
38
+ post_install_message:
39
+ rdoc_options: []
40
+
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: 1.8.6
48
+ version:
49
+ required_rubygems_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ requirements: []
56
+
57
+ rubyforge_project:
58
+ rubygems_version: 1.3.1
59
+ signing_key:
60
+ specification_version: 2
61
+ summary: Open-source Ruby framework for background processing.
62
+ test_files: []
63
+