sweatshop 1.5.2 → 1.6.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.yml +3 -3
- data/lib/message_queue/base.rb +1 -0
- data/lib/message_queue/rabbit.rb +14 -20
- data/lib/sweatshop.rb +18 -3
- data/lib/sweatshop/daemoned.rb +0 -4
- data/lib/sweatshop/metaid.rb +6 -0
- data/lib/sweatshop/sweatd.rb +2 -4
- data/lib/sweatshop/worker.rb +22 -6
- data/test/hello_worker.rb +1 -1
- data/test/test_functional_worker.rb +26 -19
- data/test/test_sweatshop.rb +2 -21
- metadata +30 -11
data/VERSION.yml
CHANGED
data/lib/message_queue/base.rb
CHANGED
data/lib/message_queue/rabbit.rb
CHANGED
@@ -7,44 +7,38 @@ module MessageQueue
|
|
7
7
|
end
|
8
8
|
|
9
9
|
def delete(queue)
|
10
|
-
|
11
|
-
client.queue(queue).delete
|
12
|
-
end
|
10
|
+
cmd(queue, :delete)
|
13
11
|
end
|
14
12
|
|
15
13
|
def queue_size(queue)
|
16
|
-
|
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
|
-
|
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
|
-
|
29
|
-
|
30
|
-
|
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
|
-
|
37
|
-
|
38
|
-
|
28
|
+
cmd(queue, :ack)
|
29
|
+
end
|
30
|
+
|
31
|
+
def flush_all(queue)
|
32
|
+
cmd(queue, :purge)
|
39
33
|
end
|
40
34
|
|
41
|
-
def
|
35
|
+
def cmd(queue, command, *args)
|
42
36
|
retried = false
|
43
37
|
begin
|
44
|
-
|
38
|
+
client.queue(queue, :durable => true).send(command, *args)
|
45
39
|
rescue Carrot::AMQP::Server::ServerDown => e
|
46
40
|
if not retried
|
47
|
-
|
41
|
+
Sweatshop.log "Error #{e.message}. Retrying..."
|
48
42
|
@client = nil
|
49
43
|
retried = true
|
50
44
|
retry
|
data/lib/sweatshop.rb
CHANGED
@@ -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
|
-
|
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|
|
192
|
+
Dir.glob(RAILS_ROOT + '/app/workers/*.rb').each{|worker| require_or_load worker }
|
178
193
|
end
|
data/lib/sweatshop/daemoned.rb
CHANGED
@@ -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
|
data/lib/sweatshop/metaid.rb
CHANGED
@@ -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
|
data/lib/sweatshop/sweatd.rb
CHANGED
data/lib/sweatshop/worker.rb
CHANGED
@@ -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
|
12
|
-
|
13
|
-
|
14
|
-
|
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
|
|
data/test/hello_worker.rb
CHANGED
@@ -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
|
-
|
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
|
-
|
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',
|
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
|
data/test/test_sweatshop.rb
CHANGED
@@ -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
|
-
|
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:
|
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
|
-
|
18
|
-
|
19
|
-
|
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
|
-
|
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
|
-
|
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.
|
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
|