sweatshop 1.5.2 → 1.6.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  ---
2
- :build:
3
- :minor: 5
4
- :patch: 2
2
+ :patch: 0
5
3
  :major: 1
4
+ :build:
5
+ :minor: 6
@@ -8,5 +8,6 @@ module MessageQueue
8
8
  def delete(queue); end
9
9
  def client; end
10
10
  def stop; end
11
+ def flush_all(queue); end
11
12
  end
12
13
  end
@@ -7,44 +7,38 @@ module MessageQueue
7
7
  end
8
8
 
9
9
  def delete(queue)
10
- send_command do
11
- client.queue(queue).delete
12
- end
10
+ cmd(queue, :delete)
13
11
  end
14
12
 
15
13
  def queue_size(queue)
16
- send_command do
17
- client.queue(queue).message_count
18
- end
14
+ cmd(queue, :message_count)
19
15
  end
20
16
 
21
17
  def enqueue(queue, data)
22
- send_command do
23
- client.queue(queue, :durable => true).publish(Marshal.dump(data), :persistent => true)
24
- end
18
+ cmd(queue, :publish, Marshal.dump(data), :persistent => true)
25
19
  end
26
20
 
27
21
  def dequeue(queue)
28
- send_command do
29
- task = client.queue(queue).pop(:ack => true)
30
- return unless task
31
- Marshal.load(task)
32
- end
22
+ task = cmd(queue, :pop, :ack => true)
23
+ return unless task
24
+ Marshal.load(task)
33
25
  end
34
26
 
35
27
  def confirm(queue)
36
- send_command do
37
- client.queue(queue).ack
38
- end
28
+ cmd(queue, :ack)
29
+ end
30
+
31
+ def flush_all(queue)
32
+ cmd(queue, :purge)
39
33
  end
40
34
 
41
- def send_command(&block)
35
+ def cmd(queue, command, *args)
42
36
  retried = false
43
37
  begin
44
- block.call
38
+ client.queue(queue, :durable => true).send(command, *args)
45
39
  rescue Carrot::AMQP::Server::ServerDown => e
46
40
  if not retried
47
- puts "Error #{e.message}. Retrying..."
41
+ Sweatshop.log "Error #{e.message}. Retrying..."
48
42
  @client = nil
49
43
  retried = true
50
44
  retry
@@ -44,6 +44,7 @@ module Sweatshop
44
44
  worker.stop
45
45
  end
46
46
  queue.stop
47
+ @stop.call if @stop.kind_of?(Proc)
47
48
  exit
48
49
  end
49
50
  sleep 1 if wait
@@ -87,8 +88,12 @@ module Sweatshop
87
88
  @daemon = true
88
89
  end
89
90
 
90
- def stop
91
- @stop = true
91
+ def stop(&block)
92
+ if block_given?
93
+ @stop = block
94
+ else
95
+ @stop = true
96
+ end
92
97
  end
93
98
 
94
99
  def stop?
@@ -125,6 +130,12 @@ module Sweatshop
125
130
  @queue_groups ||= (workers.collect{|w| w.queue_group.to_s} << 'default').uniq
126
131
  end
127
132
 
133
+ def flush_all_queues
134
+ workers.each do |worker|
135
+ worker.flush_queue
136
+ end
137
+ end
138
+
128
139
  def pp_sizes
129
140
  max_width = workers.collect{|w| w.to_s.size}.max
130
141
  puts '-' * (max_width + 10)
@@ -155,6 +166,10 @@ module Sweatshop
155
166
  nil
156
167
  end
157
168
 
169
+ def enabled?
170
+ !!config['enable']
171
+ end
172
+
158
173
  def log(msg)
159
174
  return if logger == :silent
160
175
  logger ? logger.debug(msg) : puts(msg)
@@ -174,5 +189,5 @@ module Sweatshop
174
189
  end
175
190
 
176
191
  if defined?(RAILS_ROOT)
177
- Dir.glob(RAILS_ROOT + '/app/workers/*.rb').each{|worker| require worker }
192
+ Dir.glob(RAILS_ROOT + '/app/workers/*.rb').each{|worker| require_or_load worker }
178
193
  end
@@ -49,10 +49,6 @@ module Daemoned
49
49
  options[:ontop] = true
50
50
  end
51
51
 
52
- opt.on('--instances=NUM', 'Allow multiple instances to run simultaneously? 0 for infinite. default: 1') do |value|
53
- self.instances = value.to_i
54
- end
55
-
56
52
  opt.on('--log-file=LOGFILE', 'Logfile to log to') do |value|
57
53
  options[:log_file] = File.expand_path(value)
58
54
  end
@@ -3,3 +3,9 @@ def meta_eval(&blk); metaclass.instance_eval(&blk); end
3
3
  def meta_def(name, &blk)
4
4
  meta_eval { define_method name, &blk }
5
5
  end
6
+
7
+ def check_arity!(method, args)
8
+ arity = method.arity
9
+ valid = arity < 0 ? args.size >= arity.abs - 1 : args.size == arity
10
+ raise ArgumentError.new("#{method.name} expects #{arity} arguments") unless valid
11
+ end
@@ -34,10 +34,8 @@ module Sweatshop
34
34
  end
35
35
 
36
36
  sig(:hup) do
37
- begin
38
- puts "Received HUP"
39
- Sweatshop.stop
40
- ensure
37
+ puts "Received HUP"
38
+ Sweatshop.stop do
41
39
  remove_pid!
42
40
  puts "Restarting sweatd with #{start_cmd}..."
43
41
  `#{start_cmd}`
@@ -8,12 +8,10 @@ module Sweatshop
8
8
 
9
9
  def self.method_missing(method, *args, &block)
10
10
  if method.to_s =~ /^async_(.*)/
11
- method = $1
12
- expected_args = instance.method(method).arity
13
- if expected_args != args.size
14
- raise ArgumentError.new("#{method} expects #{expected_args} arguments")
15
- end
16
- return instance.send(method, *args) unless config['enable']
11
+ method = $1
12
+ check_arity!(instance.method(method), args)
13
+
14
+ return instance.send(method, *args) unless async?
17
15
 
18
16
  uid = ::Digest::MD5.hexdigest("#{name}:#{method}:#{args}:#{Time.now.to_f}")
19
17
  task = {:args => args, :method => method, :uid => uid, :queued_at => Time.now.to_i}
@@ -29,6 +27,10 @@ module Sweatshop
29
27
  end
30
28
  end
31
29
 
30
+ def self.async?
31
+ Sweatshop.enabled?
32
+ end
33
+
32
34
  def self.instance
33
35
  @instance ||= new
34
36
  end
@@ -41,6 +43,10 @@ module Sweatshop
41
43
  @queue_name ||= self.to_s
42
44
  end
43
45
 
46
+ def self.flush_queue
47
+ queue.flush_all(queue_name)
48
+ end
49
+
44
50
  def self.delete_queue
45
51
  queue.delete(queue_name)
46
52
  end
@@ -82,6 +88,16 @@ module Sweatshop
82
88
  rescue Exception => e
83
89
  log("Caught Exception: #{e.message}, \n#{e.backtrace.join("\n")}")
84
90
  call_exception_handler(e)
91
+
92
+ # the only way to re-queue messages with rabbitmq is to close and reopen the connection
93
+ # putting a 'sleep 2' in here to give the administrator to fix peristent problems, otherwise
94
+ # we'll hit an infinite loop
95
+ #
96
+ # THIS CODE IS PROBLEMATIC --- we need to put these tasks into a 'failed' queue so we don't run into infinite loops
97
+ # will just 'confirm' for now
98
+ #queue.stop
99
+ #sleep 2
100
+ confirm
85
101
  end
86
102
  end
87
103
 
@@ -1,4 +1,4 @@
1
- require File.dirname(__FILE__) + '/../lib/sweatshop'
1
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/sweatshop')
2
2
  class HelloWorker < Sweatshop::Worker
3
3
  TEST_FILE = File.dirname(__FILE__) + '/test.txt' unless defined?(TEST_FILE)
4
4
 
@@ -1,6 +1,6 @@
1
- require File.dirname(__FILE__) + '/../lib/sweatshop'
2
- require File.dirname(__FILE__) + '/test_helper'
3
- require File.dirname(__FILE__) + '/hello_worker'
1
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/sweatshop')
2
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper' )
3
+ require File.expand_path(File.dirname(__FILE__) + '/hello_worker' )
4
4
 
5
5
  class WorkerTest < Test::Unit::TestCase
6
6
 
@@ -15,10 +15,7 @@ class WorkerTest < Test::Unit::TestCase
15
15
  end
16
16
 
17
17
  should "daemonize" do
18
- begin
19
- Sweatshop.config['enable'] = true
20
- Sweatshop.logger = :silent
21
-
18
+ enable_server do
22
19
  HelloWorker.async_hello('Amos')
23
20
 
24
21
  worker = File.expand_path(File.dirname(__FILE__) + '/hello_worker')
@@ -29,26 +26,19 @@ class WorkerTest < Test::Unit::TestCase
29
26
 
30
27
  File.delete('sweatd.log') if File.exist?('sweatd.log')
31
28
  assert_equal 'Hi, Amos', File.read(HelloWorker::TEST_FILE)
32
-
33
- rescue Exception => e
34
- puts e.message
35
- puts e.backtrace.join("\n")
36
- fail "\n\n*** Functional test failed, is the rabbit server running on localhost? ***\n"
37
29
  end
38
30
  end
39
31
 
40
32
  should "connect to fallback servers if the default one is down" do
41
- begin
42
- Sweatshop.logger = :silent
43
- Sweatshop.config['enable'] = true
33
+ enable_server do
44
34
  Sweatshop.config['default']['cluster'] =
45
35
  [
46
36
  'localhost:5671', # invalid
47
37
  'localhost:5672' # valid
48
38
  ]
49
39
  HelloWorker.async_hello('Amos')
50
-
51
- assert_equal 'Amos', HelloWorker.dequeue[:args].first
40
+ task = HelloWorker.dequeue
41
+ assert_equal 'Amos', task[:args].first
52
42
 
53
43
  HelloWorker.queue.client = nil
54
44
 
@@ -61,12 +51,29 @@ class WorkerTest < Test::Unit::TestCase
61
51
 
62
52
  HelloWorker.async_hello('Amos')
63
53
  assert_equal 'Amos', HelloWorker.dequeue[:args].first
64
-
54
+ end
55
+ end
56
+
57
+ should "exception handler" do
58
+ exception = nil
59
+ HelloWorker.on_exception do |e|
60
+ exception = e
61
+ end
62
+
63
+ HelloWorker.do_task(nil)
64
+ assert_equal NoMethodError, exception.class
65
+ end
66
+
67
+
68
+ def enable_server
69
+ Sweatshop.config['enable'] = true
70
+ Sweatshop.logger = :silent
71
+ begin
72
+ yield
65
73
  rescue Exception => e
66
74
  puts e.message
67
75
  puts e.backtrace.join("\n")
68
76
  fail "\n\n*** Functional test failed, is the rabbit server running on localhost? ***\n"
69
77
  end
70
78
  end
71
-
72
79
  end
@@ -1,5 +1,5 @@
1
- require File.dirname(__FILE__) + '/test_helper'
2
- require File.dirname(__FILE__) + '/../lib/sweatshop'
1
+ require File.expand_path(File.dirname(__FILE__) + '/test_helper' )
2
+ require File.expand_path(File.dirname(__FILE__) + '/../lib/sweatshop')
3
3
 
4
4
  class SweatshopTest < Test::Unit::TestCase
5
5
  Sweatshop.workers = []
@@ -25,13 +25,6 @@ class SweatshopTest < Test::Unit::TestCase
25
25
  assert_equal "Hi, Amos", worker.hello('Amos')
26
26
  end
27
27
 
28
- should "assign a uid" do
29
- Sweatshop.logger = :silent
30
- Sweatshop.config['enable'] = false
31
- uid = HelloWorker.async_hello('Amos')
32
- assert_not_nil uid
33
- end
34
-
35
28
  should "have before task" do
36
29
  HelloWorker.before_task do
37
30
  "hello"
@@ -46,18 +39,6 @@ class SweatshopTest < Test::Unit::TestCase
46
39
  assert_equal "goodbye", HelloWorker.after_task.call
47
40
  end
48
41
 
49
- should "exception handler" do
50
- Sweatshop.logger = :silent
51
-
52
- exception = nil
53
- HelloWorker.on_exception do |e|
54
- exception = e
55
- end
56
-
57
- HelloWorker.do_task(nil)
58
- assert_equal NoMethodError, exception.class
59
- end
60
-
61
42
  should "chain before tasks" do
62
43
  MESSAGES = []
63
44
  class BaseWorker < Sweatshop::Worker
metadata CHANGED
@@ -1,7 +1,13 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sweatshop
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.5.2
4
+ hash: 15
5
+ prerelease: false
6
+ segments:
7
+ - 1
8
+ - 6
9
+ - 0
10
+ version: 1.6.0
5
11
  platform: ruby
6
12
  authors:
7
13
  - Amos Elliston
@@ -9,19 +15,25 @@ autorequire:
9
15
  bindir: bin
10
16
  cert_chain: []
11
17
 
12
- date: 2010-01-03 00:00:00 -08:00
18
+ date: 2011-04-05 00:00:00 -07:00
13
19
  default_executable: sweatd
14
20
  dependencies:
15
21
  - !ruby/object:Gem::Dependency
16
22
  name: carrot
17
- type: :runtime
18
- version_requirement:
19
- version_requirements: !ruby/object:Gem::Requirement
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
20
26
  requirements:
21
27
  - - "="
22
28
  - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ - 7
33
+ - 0
23
34
  version: 0.7.0
24
- version:
35
+ type: :runtime
36
+ version_requirements: *id001
25
37
  description: See summary
26
38
  email: amos@geni.com
27
39
  executables:
@@ -56,31 +68,38 @@ files:
56
68
  - test/test_functional_worker.rb
57
69
  - test/test_helper.rb
58
70
  - test/test_sweatshop.rb
71
+ - bin/sweatd
59
72
  has_rdoc: true
60
73
  homepage: http://github.com/famoseagle/sweatshop
61
74
  licenses: []
62
75
 
63
76
  post_install_message:
64
- rdoc_options:
65
- - --charset=UTF-8
77
+ rdoc_options: []
78
+
66
79
  require_paths:
67
80
  - lib
68
81
  required_ruby_version: !ruby/object:Gem::Requirement
82
+ none: false
69
83
  requirements:
70
84
  - - ">="
71
85
  - !ruby/object:Gem::Version
86
+ hash: 3
87
+ segments:
88
+ - 0
72
89
  version: "0"
73
- version:
74
90
  required_rubygems_version: !ruby/object:Gem::Requirement
91
+ none: false
75
92
  requirements:
76
93
  - - ">="
77
94
  - !ruby/object:Gem::Version
95
+ hash: 3
96
+ segments:
97
+ - 0
78
98
  version: "0"
79
- version:
80
99
  requirements: []
81
100
 
82
101
  rubyforge_project:
83
- rubygems_version: 1.3.5
102
+ rubygems_version: 1.3.7
84
103
  signing_key:
85
104
  specification_version: 3
86
105
  summary: Sweatshop is a simple asynchronous worker queue build on top of rabbitmq/ampq