refinery 0.9.15 → 0.10.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.
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.9.15
1
+ 0.10.0
@@ -1,6 +1,6 @@
1
1
  module Refinery #:nodoc:
2
2
  # A daemon provides a thread to run workers in.
3
- class Daemon
3
+ class Daemon < Thread
4
4
  include Refinery::Loggable
5
5
  include Refinery::Configurable
6
6
  include Refinery::Utilities
@@ -9,8 +9,6 @@ module Refinery #:nodoc:
9
9
  RUNNING = 'running'
10
10
  STOPPED = 'stopped'
11
11
 
12
- # The daemon's thread
13
- attr_reader :thread
14
12
  # The name of the daemon
15
13
  attr_reader :name
16
14
  # The settings for the daemon
@@ -41,7 +39,7 @@ module Refinery #:nodoc:
41
39
 
42
40
  # Initialize the daemon.
43
41
  #
44
- # * <tt>server</tt>: The server instance
42
+ # * <tt>processor</tt>: The processor instance
45
43
  # * <tt>name</tt>: The processor name
46
44
  # * <tt>waiting_queue</tt>: The waiting queue that provides messages to be processed
47
45
  # * <tt>error_queue</tt>: The queue where errors are posted.
@@ -51,10 +49,10 @@ module Refinery #:nodoc:
51
49
  # The settings hash may contain the following options:
52
50
  # * <tt>visibility</tt>: The time in seconds that the message is hidden
53
51
  # in the queue.
54
- def initialize(server, name, queue_prefix='', settings={})
55
- Refinery::Server.logger.debug "Starting daemon"
52
+ def initialize(processor, name, queue_prefix='', settings={})
53
+ logger.debug "Starting daemon"
56
54
 
57
- @server = server
55
+ @processor = processor
58
56
  @name = name
59
57
  @settings = settings
60
58
 
@@ -63,49 +61,59 @@ module Refinery #:nodoc:
63
61
  logger.debug "Using queue #{queue_name}"
64
62
  @queue_name = queue_name
65
63
 
66
- @thread = Thread.new(self) do |daemon|
67
- logger.debug "Running daemon thread: #{name} (settings: #{settings.inspect})"
68
- while(running?)
69
- with_queue("#{queue_name}_waiting") do |waiting_queue|
70
- while (message = waiting_queue.receive(settings['visibility']))
71
- worker = load_worker_class(name).new(self)
72
- begin
73
- result, run_time = worker.run(decode_message(message.body))
74
- if result
75
- with_queue("#{queue_name}_done") do |done_queue|
76
- done_message = {
77
- 'host_info' => host_info,
78
- 'original' => message.body,
79
- 'run_time' => run_time
80
- }
81
- logger.debug "Sending 'done' message to #{done_queue.name}"
82
- done_queue.send_message(encode_message(done_message))
83
- end
84
-
85
- logger.debug "Deleting message from queue"
86
- message.delete()
87
- end
88
- rescue Exception => e
89
- with_queue("#{queue_name}_error") do |error_queue|
90
- error_message = {
91
- 'error' => {
92
- 'message' => e.message,
93
- 'class' => e.class.name
94
- },
64
+ super do
65
+ begin
66
+ execute
67
+ rescue Exception => e
68
+ logger.error e
69
+ end
70
+ end
71
+ end
72
+
73
+ private
74
+ def execute
75
+ logger.debug "Running daemon thread: #{name} (settings: #{settings.inspect})"
76
+ while(running?)
77
+ #logger.debug "Checking #{queue_name}_waiting"
78
+ with_queue("#{queue_name}_waiting") do |waiting_queue|
79
+ while (message = waiting_queue.receive(settings['visibility']))
80
+ worker = load_worker_class(name).new(self)
81
+ begin
82
+ result, run_time = worker.run(decode_message(message.body))
83
+ if result
84
+ with_queue("#{queue_name}_done") do |done_queue|
85
+ done_message = {
95
86
  'host_info' => host_info,
96
- 'original' => message.body
87
+ 'original' => message.body,
88
+ 'run_time' => run_time
97
89
  }
98
- logger.error "Sending 'error' message to #{error_queue.name}: #{e.message}"
99
- error_queue.send_message(encode_message(error_message))
90
+ logger.debug "Sending 'done' message to #{done_queue.name}"
91
+ done_queue.send_message(encode_message(done_message))
100
92
  end
93
+
94
+ logger.debug "Deleting message from queue"
101
95
  message.delete()
102
96
  end
97
+ rescue Exception => e
98
+ with_queue("#{queue_name}_error") do |error_queue|
99
+ error_message = {
100
+ 'error' => {
101
+ 'message' => e.message,
102
+ 'class' => e.class.name
103
+ },
104
+ 'host_info' => host_info,
105
+ 'original' => message.body
106
+ }
107
+ logger.error "Sending 'error' message to #{error_queue.name}: #{e.message}"
108
+ error_queue.send_message(encode_message(error_message))
109
+ end
110
+ message.delete()
103
111
  end
104
- sleep(settings['sleep'] || 5)
105
112
  end
113
+ sleep(settings['sleep'] || 5)
106
114
  end
107
- logger.debug "Exiting daemon thread"
108
115
  end
116
+ logger.debug "Exiting daemon thread"
109
117
  end
110
118
 
111
119
  # A hash of worker classes
@@ -116,7 +124,7 @@ module Refinery #:nodoc:
116
124
  private
117
125
  # Load the appropriate worker class
118
126
  def load_worker_class(name)
119
- source_file = "#{@server.workers_directory}/#{name}.rb"
127
+ source_file = "#{@processor.server.workers_directory}/#{name}.rb"
120
128
  if File.exist?(source_file)
121
129
  modified_at = File.mtime(source_file)
122
130
  if workers[name] != modified_at
@@ -0,0 +1,49 @@
1
+ module Refinery #:nodoc:
2
+ # This class is used to monitor all of the threads for a single
3
+ # processor.
4
+ class Processor < Thread
5
+ include Refinery::Configurable
6
+ include Refinery::Loggable
7
+
8
+ attr_reader :server
9
+ attr_reader :key
10
+ attr_reader :settings
11
+ attr_reader :daemons
12
+
13
+ # Initialize the processor.
14
+ def initialize(server, key, settings={})
15
+ @server = server
16
+ @key = key
17
+ @settings = settings
18
+ @daemons = []
19
+ super do
20
+ execute
21
+ end
22
+ end
23
+
24
+ private
25
+ # Execute the processor
26
+ def execute
27
+ queue_prefix = config['prefix'] || ''
28
+
29
+ logger.debug "Creating daemons for #{key}"
30
+ 1.upto(settings['workers']['initial']) do
31
+ daemons << Daemon.new(self, key, queue_prefix, settings)
32
+ end
33
+
34
+ logger.debug "Running #{daemons.length} daemons"
35
+
36
+ wait = ThreadsWait.new(*daemons)
37
+ wait.all_waits do |daemon|
38
+ puts "a #{daemon.name} just died"
39
+ daemons.remove(daemon)
40
+ puts "starting a new #{key} daemon"
41
+ daemon = Daemon.new(self, key, queue_prefix, settings)
42
+ daemons << daemon
43
+ wait.join(daemon)
44
+ end
45
+
46
+ logger.debug "Processor #{key} is exiting"
47
+ end
48
+ end
49
+ end
@@ -19,9 +19,24 @@ module Refinery #:nodoc:
19
19
  # into the queue associated with the publisher.
20
20
  def publish(message)
21
21
  with_queue(waiting_queue_name) do |waiting_queue|
22
- logger.debug "Publisher #{self.class.name} sending message: #{message.to_json}"
23
- waiting_queue.send_message(Base64.encode64(message.to_json))
22
+ publish_to_queue(waiting_queue, message)
24
23
  end
25
24
  end
25
+
26
+ # Publish the given message if the waiting queue is empty. The message will
27
+ # be converted to JSON and pushed into the queue associated with the
28
+ # publisher.
29
+ def publish_if_empty(message)
30
+ with_queue(waiting_queue_name) do |waiting_queue|
31
+ publish_to_queue(waiting_queue, message) if waiting_queue.size == 0
32
+ end
33
+ end
34
+
35
+ # Publish the given message to the queue. The message will be converted
36
+ # to JSON and pushed into the queue associated with the publisher.
37
+ def publish_to_queue(queue, message)
38
+ logger.debug "Publisher #{self.class.name} sending message: #{message.to_json}"
39
+ queue.send_message(Base64.encode64(message.to_json))
40
+ end
26
41
  end
27
42
  end
@@ -9,24 +9,9 @@ module Refinery #:nodoc:
9
9
  end
10
10
 
11
11
  # Given the queue name and a block, yield the named queue into
12
- # the block. This method handles any exceptions that are raised
13
- # in the block and will recreate the provider automatically.
14
- #
15
- # Note that errors will not be propagated beyond this block. You
16
- # have been warned.
12
+ # the block.
17
13
  def with_queue(name, &block)
18
- begin
19
- yield queue(name)
20
- rescue Exception => e
21
- logger.error "Queue error: #{e.message}"
22
- # this removes the sqs connection from the current thread.
23
- # note that this is brittle and will break if the RightAWS
24
- # library changes the name or the way the sqs connection is
25
- # stored in the thread local hash
26
- Thread.current[:sqs_connection] = nil
27
- sleep(5)
28
- retry
29
- end
14
+ yield queue(name)
30
15
  end
31
16
 
32
17
  protected
@@ -54,26 +54,21 @@ module Refinery #:nodoc:
54
54
  # Run the server
55
55
  def run
56
56
  logger.info "Starting Refinery server"
57
- execute_daemons
57
+ execute_processors
58
58
  logger.info "Server is exiting"
59
59
  end
60
60
 
61
61
  private
62
- def execute_daemons
63
- queue_prefix = config['prefix'] || ''
64
- config['processors'].each do |key, settings|
65
- logger.debug "Creating daemons for #{key}"
66
- 1.upto(settings['workers']['initial']) do
67
- daemons << Refinery::Daemon.new(self, key, queue_prefix, settings)
68
- end
69
-
70
- logger.debug "Running #{daemons.length} daemons"
62
+ def execute_processors
63
+
64
+ @processors = config['processors'].map do |key, settings|
65
+ Processor.new(self, key, settings)
71
66
  end
72
67
 
73
68
  Heartbeat.new(self)
74
69
 
75
70
  begin
76
- daemons.each { |daemon| daemon.thread.join }
71
+ @processors.each { |p| p.join }
77
72
  rescue Interrupt => e
78
73
  end
79
74
  end
data/lib/refinery.rb CHANGED
@@ -45,6 +45,8 @@ module Refinery
45
45
 
46
46
  # Require internal code files
47
47
  def self.require_internals
48
+ require 'thwait'
49
+
48
50
  require 'refinery/loggable'
49
51
  require 'refinery/configurable'
50
52
  require 'refinery/queueable'
@@ -56,6 +58,7 @@ module Refinery
56
58
  require 'refinery/config'
57
59
  require 'refinery/heartbeat'
58
60
  require 'refinery/server'
61
+ require 'refinery/processor'
59
62
  require 'refinery/daemon'
60
63
  require 'refinery/worker'
61
64
  require 'refinery/event_publisher'
data/publishers/error.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  # An example publisher that posts a message to the queue that should raise an error.
2
2
  class ErrorPublisher < Refinery::Publisher
3
3
  def execute
4
- if waiting_queue.size == 0
5
- publish({'text' => 'fire an error, please'})
6
- end
4
+ publish_if_empty({'text' => 'fire an error, please'})
7
5
  end
8
6
  end
data/publishers/sample.rb CHANGED
@@ -1,8 +1,6 @@
1
1
  # A sample publisher that posts a message to the queue.
2
2
  class SamplePublisher < Refinery::Publisher
3
3
  def execute
4
- if waiting_queue.size == 0
5
- publish({'text' => 'hey there!'})
6
- end
4
+ publish_if_empty({'text' => 'hey there!'})
7
5
  end
8
6
  end
data/publishers/sleep.rb CHANGED
@@ -1,7 +1,5 @@
1
1
  class SleepPublisher < Refinery::Publisher
2
2
  def execute
3
- if waiting_queue.size == 0
4
- publish({'seconds' => rand(5) + 0.5})
5
- end
3
+ publish({'seconds' => rand(5) + 0.5})
6
4
  end
7
5
  end
data/refinery.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{refinery}
5
- s.version = "0.9.15"
5
+ s.version = "0.10.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Anthony Eden"]
9
- s.date = %q{2009-07-11}
9
+ s.date = %q{2009-07-13}
10
10
  s.description = %q{Process data in a distributed fashion.}
11
11
  s.email = %q{anthonyeden@gmail.com}
12
12
  s.executables = ["epub", "monitor", "pubnow", "refinery"]
@@ -37,6 +37,7 @@ Gem::Specification.new do |s|
37
37
  "lib/refinery/heartbeat.rb",
38
38
  "lib/refinery/loggable.rb",
39
39
  "lib/refinery/monitor.rb",
40
+ "lib/refinery/processor.rb",
40
41
  "lib/refinery/publisher.rb",
41
42
  "lib/refinery/queueable.rb",
42
43
  "lib/refinery/server.rb",
@@ -58,6 +59,7 @@ Gem::Specification.new do |s|
58
59
  "test/unit/event_publisher_test.rb",
59
60
  "test/unit/heartbeat_test.rb",
60
61
  "test/unit/loggable_test.rb",
62
+ "test/unit/processor_test.rb",
61
63
  "test/unit/publisher_test.rb",
62
64
  "test/unit/queueable_test.rb",
63
65
  "test/unit/server_test.rb",
@@ -84,6 +86,7 @@ Gem::Specification.new do |s|
84
86
  "test/unit/event_publisher_test.rb",
85
87
  "test/unit/heartbeat_test.rb",
86
88
  "test/unit/loggable_test.rb",
89
+ "test/unit/processor_test.rb",
87
90
  "test/unit/publisher_test.rb",
88
91
  "test/unit/queueable_test.rb",
89
92
  "test/unit/server_test.rb",
@@ -3,6 +3,8 @@ class DaemonTest < Test::Unit::TestCase
3
3
  context "a daemon" do
4
4
  setup do
5
5
  @server = stub('Server')
6
+ @processor = stub('Processor', :server => @server)
7
+
6
8
  @waiting_queue = stub('Queue(waiting)')
7
9
  @error_queue = stub('Queue(error)')
8
10
  @done_queue = stub('Queue(done)')
@@ -17,41 +19,41 @@ class DaemonTest < Test::Unit::TestCase
17
19
  should "be startable" do
18
20
  @waiting_queue.stubs(:receive)
19
21
  assert_nothing_raised do
20
- daemon = Refinery::Daemon.new(@server, 'sample')
22
+ daemon = Refinery::Daemon.new(@processor, 'sample')
21
23
  end
22
24
  end
23
25
  should "have logging" do
24
26
  @waiting_queue.stubs(:receive)
25
- daemon = Refinery::Daemon.new(@server, 'sample')
27
+ daemon = Refinery::Daemon.new(@processor, 'sample')
26
28
  assert_not_nil daemon.logger
27
29
  end
28
30
  should "allow visibility setting" do
29
31
  @waiting_queue.expects(:receive).with(600)
30
- daemon = Refinery::Daemon.new(@server, 'sample', '', {'visibility' => 600})
32
+ daemon = Refinery::Daemon.new(@processor, 'sample', '', {'visibility' => 600})
31
33
  end
32
34
  should "have a queue name" do
33
35
  @waiting_queue.stubs(:receive)
34
- Refinery::Daemon.any_instance.stubs(:queue).with(
36
+ Refinery::Daemon.any_instance.expects(:queue).with(
35
37
  'prefix_sample_waiting').returns(@waiting_queue)
36
- daemon = Refinery::Daemon.new(@server, 'sample', 'prefix_')
38
+ daemon = Refinery::Daemon.new(@processor, 'sample', 'prefix_')
37
39
  assert_equal 'prefix_sample', daemon.queue_name
38
40
  end
39
41
  context "that is started" do
40
42
  setup do
41
43
  @waiting_queue.stubs(:receive)
42
- @daemon = Refinery::Daemon.new(@server, 'sample')
44
+ @daemon = Refinery::Daemon.new(@processor, 'sample')
43
45
  end
44
46
  should "have a state of running" do
45
47
  assert @daemon.running?
46
48
  end
47
- context "after calling stop" do
48
- setup do
49
- @daemon.stop
50
- end
51
- should "not be running" do
52
- assert !@daemon.running?
53
- end
54
- end
49
+ # context "after calling stop" do
50
+ # setup do
51
+ # @daemon.stop
52
+ # end
53
+ # should "not be running" do
54
+ # assert !@daemon.running?
55
+ # end
56
+ # end
55
57
  end
56
58
  end
57
59
  end
@@ -0,0 +1,30 @@
1
+ require File.dirname(__FILE__) + '/../test_helper'
2
+ class ProcessorTest < Test::Unit::TestCase
3
+ context "a processor" do
4
+ setup do
5
+ @server = stub('Server')
6
+ @settings = {
7
+ 'workers' => {
8
+ 'initial' => 1
9
+ }
10
+ }
11
+
12
+ @waiting_queue = stub('Queue(waiting)')
13
+ @error_queue = stub('Queue(error)')
14
+ @done_queue = stub('Queue(done)')
15
+
16
+ Refinery::Daemon.any_instance.stubs(:queue).with(
17
+ 'sample_waiting').returns(@waiting_queue)
18
+ Refinery::Daemon.any_instance.stubs(:queue).with(
19
+ 'sample_error').returns(@error_queue)
20
+ Refinery::Daemon.any_instance.stubs(:queue).with(
21
+ 'sample_done').returns(@done_queue)
22
+ end
23
+ should "initialize" do
24
+ assert_nothing_raised do
25
+ @waiting_queue.stubs(:receive)
26
+ Refinery::Processor.new(@server, 'sample', @settings)
27
+ end
28
+ end
29
+ end
30
+ end
@@ -20,13 +20,7 @@ class ServerTest < Test::Unit::TestCase
20
20
  should "be runnable" do
21
21
  setup_default_config
22
22
 
23
- heartbeat_queue = stub('heartbeat queue')
24
- heartbeat_queue.stubs(:send_message)
25
- queue_provider = stub('queue provider')
26
- queue_provider.expects(:queue).with('heartbeat').returns(heartbeat_queue)
27
- RightAws::SqsGen2.expects(:new).with(
28
- 'aki', 'sak', {:multi_thread => true}
29
- ).returns(queue_provider)
23
+ Refinery::Heartbeat.expects(:new)
30
24
 
31
25
  assert_nothing_raised do
32
26
  thread = Thread.new do
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: refinery
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.15
4
+ version: 0.10.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Anthony Eden
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-11 00:00:00 -04:00
12
+ date: 2009-07-13 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
@@ -48,6 +48,7 @@ files:
48
48
  - lib/refinery/heartbeat.rb
49
49
  - lib/refinery/loggable.rb
50
50
  - lib/refinery/monitor.rb
51
+ - lib/refinery/processor.rb
51
52
  - lib/refinery/publisher.rb
52
53
  - lib/refinery/queueable.rb
53
54
  - lib/refinery/server.rb
@@ -69,6 +70,7 @@ files:
69
70
  - test/unit/event_publisher_test.rb
70
71
  - test/unit/heartbeat_test.rb
71
72
  - test/unit/loggable_test.rb
73
+ - test/unit/processor_test.rb
72
74
  - test/unit/publisher_test.rb
73
75
  - test/unit/queueable_test.rb
74
76
  - test/unit/server_test.rb
@@ -113,6 +115,7 @@ test_files:
113
115
  - test/unit/event_publisher_test.rb
114
116
  - test/unit/heartbeat_test.rb
115
117
  - test/unit/loggable_test.rb
118
+ - test/unit/processor_test.rb
116
119
  - test/unit/publisher_test.rb
117
120
  - test/unit/queueable_test.rb
118
121
  - test/unit/server_test.rb