dyoder-hive 0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/lib/scheduler.rb +70 -0
  2. data/lib/worker.rb +103 -0
  3. metadata +63 -0
data/lib/scheduler.rb ADDED
@@ -0,0 +1,70 @@
1
+ require 'rubygems'
2
+ require 'facets/duration' unless 1.respond_to? :minute
3
+
4
+ module Hive
5
+
6
+ class Scheduler < Hive::Worker
7
+
8
+ def stop_tasks
9
+ threads = Thread.list.select { |t| t.alive? && t != Thread.current }
10
+ until threads.empty?
11
+ logger.info "#{threads.count} threads still running ... "
12
+ threads.each { |t| t.kill && t != Thread.current }
13
+ threads = threads.select { |t| t.alive? }
14
+ end
15
+ logger.info "All threads are finished."
16
+ end
17
+
18
+ private
19
+
20
+ def schedule( method, options )
21
+ raise ArgumentError.new( "Invalid schedule for task #{method}.") unless valid?(options)
22
+ logger.info "Scheduling task #{method} ..."
23
+ Thread.new do
24
+ t = Time.now
25
+ loop do
26
+ t += 60
27
+ sleep( ( options[:interval] || ( t - Time.now ) ).to_i )
28
+ if match( t, options )
29
+ if self.respond_to?( method )
30
+ Thread.new do
31
+ logger.info "Running task #{method} ..."
32
+ self.send( method )
33
+ logger.info "Task #{method} complete."
34
+ end
35
+ else
36
+ logger.warn "Task #{method} scheduled but not defined."
37
+ end
38
+ end
39
+ end
40
+ end
41
+ end
42
+
43
+ def valid?( options )
44
+ ! ( options.keys & [ :minute, :hour, :day, :weekday, :month, :interval] ).empty?
45
+ end
46
+
47
+ def match( t, options )
48
+ options[:interval] ||
49
+ (( match_item( options[:minute], t.min )) &&
50
+ ( match_item( options[:hour], t.hour )) &&
51
+ ( match_item( options[:day], t.day )) &&
52
+ ( match_item( options[:weekday], t.wday )) &&
53
+ ( match_item( options[:month], t.month )))
54
+ end
55
+
56
+ def match_item( x, y )
57
+ case x
58
+ when nil then true
59
+ when Array then x.include? y
60
+ when Range then x.include? y
61
+ when Integer then x == y
62
+ else
63
+ logger.warn "Value #{x.inspect} will never be matched"
64
+ false
65
+ end
66
+ end
67
+
68
+ end
69
+
70
+ end
data/lib/worker.rb ADDED
@@ -0,0 +1,103 @@
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
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
+ File.umask 0000 ; STDIN.reopen( '/dev/null') ;
60
+ STDOUT.reopen( '/dev/null', 'a' ) ; STDERR.reopen( STDOUT )
61
+ nil # return nil for child process, just like fork does
62
+ end
63
+
64
+ def set_traps
65
+ safe_trap( 'HUP' ) { restart }
66
+ safe_trap( 'TERM','INT' ) { stop }
67
+ end
68
+
69
+ def start_console
70
+ # TODO: add live console support
71
+ end
72
+
73
+ def start_drb
74
+ # TODO: add DRb support
75
+ end
76
+
77
+ def start_debugger
78
+ require 'ruby-debug' ; Debugger.start
79
+ Debugger.settings[:autoeval] = true if Debugger.respond_to?(:settings)
80
+ logger.info "ruby-debug enabled"
81
+ end
82
+
83
+ def start_logger
84
+ if options[ :logger ]
85
+ @logger = options[ :logger ]
86
+ else
87
+ require 'logger'
88
+ @logger = Logger.new( 'log.out' )
89
+ end
90
+ end
91
+
92
+ protected
93
+
94
+ # workers should override these methods
95
+ def start_tasks
96
+ end
97
+
98
+ def stop_tasks
99
+ end
100
+
101
+ end
102
+
103
+ end
metadata ADDED
@@ -0,0 +1,63 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dyoder-hive
3
+ version: !ruby/object:Gem::Version
4
+ version: "0.1"
5
+ platform: ruby
6
+ authors:
7
+ - Dan Yoder
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+
12
+ date: 2009-06-01 00:00:00 -07:00
13
+ default_executable:
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: faces/duration
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/scheduler.rb
35
+ - lib/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.7
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.2.0
59
+ signing_key:
60
+ specification_version: 2
61
+ summary: Open-source Ruby framework for background processing.
62
+ test_files: []
63
+