rcelery 1.0.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/Gemfile +3 -0
- data/LICENSE +27 -0
- data/Rakefile +34 -0
- data/bin/rceleryd +7 -0
- data/lib/rcelery/async_result.rb +23 -0
- data/lib/rcelery/configuration.rb +25 -0
- data/lib/rcelery/daemon.rb +82 -0
- data/lib/rcelery/eager_result.rb +10 -0
- data/lib/rcelery/events.rb +103 -0
- data/lib/rcelery/pool.rb +59 -0
- data/lib/rcelery/rails.rb +29 -0
- data/lib/rcelery/railtie.rb +11 -0
- data/lib/rcelery/task/context.rb +25 -0
- data/lib/rcelery/task/runner.rb +73 -0
- data/lib/rcelery/task.rb +118 -0
- data/lib/rcelery/task_support.rb +56 -0
- data/lib/rcelery/version.rb +6 -0
- data/lib/rcelery/worker.rb +76 -0
- data/lib/rcelery.rb +86 -0
- data/rails/init.rb +4 -0
- data/rcelery.gemspec +28 -0
- data/spec/bin/ci +81 -0
- data/spec/integration/Procfile +4 -0
- data/spec/integration/bin/celeryd +4 -0
- data/spec/integration/bin/rabbitmq-server +4 -0
- data/spec/integration/bin/rceleryd +4 -0
- data/spec/integration/python_components/celery_client.py +5 -0
- data/spec/integration/python_components/celery_deferred_client.py +10 -0
- data/spec/integration/python_components/celeryconfig.py +26 -0
- data/spec/integration/python_components/requirements.txt +9 -0
- data/spec/integration/python_components/tasks.py +13 -0
- data/spec/integration/ruby_client_python_worker_spec.rb +17 -0
- data/spec/integration/ruby_worker_spec.rb +115 -0
- data/spec/integration/spec_helper.rb +43 -0
- data/spec/integration/tasks.rb +37 -0
- data/spec/spec_helper.rb +34 -0
- data/spec/unit/configuration_spec.rb +91 -0
- data/spec/unit/daemon_spec.rb +21 -0
- data/spec/unit/eager_spec.rb +46 -0
- data/spec/unit/events_spec.rb +149 -0
- data/spec/unit/pool_spec.rb +124 -0
- data/spec/unit/rails_spec.rb +0 -0
- data/spec/unit/rcelery_spec.rb +154 -0
- data/spec/unit/task_spec.rb +192 -0
- data/spec/unit/task_support_spec.rb +94 -0
- data/spec/unit/worker_spec.rb +63 -0
- metadata +290 -0
@@ -0,0 +1,76 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'forwardable'
|
3
|
+
require 'json'
|
4
|
+
require 'benchmark'
|
5
|
+
|
6
|
+
module RCelery
|
7
|
+
class Worker
|
8
|
+
include Task::States
|
9
|
+
|
10
|
+
class << self
|
11
|
+
extend Forwardable
|
12
|
+
def_delegators :start, :stop, :join
|
13
|
+
end
|
14
|
+
|
15
|
+
def initialize
|
16
|
+
@heartbeat = 60
|
17
|
+
@poll_interval = 0.5
|
18
|
+
|
19
|
+
@ident = 'rcelery'
|
20
|
+
@version = RCelery::VERSION
|
21
|
+
@system = RUBY_PLATFORM
|
22
|
+
end
|
23
|
+
|
24
|
+
def start(pool)
|
25
|
+
RCelery::Events.worker_online(@ident, @version, @system)
|
26
|
+
@pool = pool
|
27
|
+
start_heartbeat
|
28
|
+
subscribe
|
29
|
+
end
|
30
|
+
|
31
|
+
def subscribe
|
32
|
+
loop do
|
33
|
+
consume @pool.poll
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def stop
|
38
|
+
stop_heartbeat
|
39
|
+
RCelery::Events.worker_offline(@ident, @version, @system)
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
def start_heartbeat
|
44
|
+
@heartbeat_timer = EM.add_periodic_timer(@heartbeat) do
|
45
|
+
RCelery::Events.worker_heartbeat(@ident, @version, @system)
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
def stop_heartbeat
|
50
|
+
@heartbeat_timer.cancel unless @heartbeat_timer.nil?
|
51
|
+
end
|
52
|
+
|
53
|
+
def consume(data)
|
54
|
+
message = data[:message]
|
55
|
+
header = data[:header]
|
56
|
+
|
57
|
+
RCelery::Events.task_started(message['id'], Process.pid)
|
58
|
+
|
59
|
+
runner = nil
|
60
|
+
runtime = Benchmark.realtime do
|
61
|
+
runner = Task.execute(message)
|
62
|
+
end
|
63
|
+
|
64
|
+
case runner.status
|
65
|
+
when SUCCESS
|
66
|
+
RCelery::Events.task_succeeded(message['id'], runner.result, runtime)
|
67
|
+
when RETRY
|
68
|
+
RCelery::Events.task_retried(message['id'], runner.result, runner.result.backtrace)
|
69
|
+
when FAILURE
|
70
|
+
RCelery::Events.task_failed(message['id'], runner.result, runner.result.backtrace)
|
71
|
+
end
|
72
|
+
|
73
|
+
header.ack
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
data/lib/rcelery.rb
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'amqp'
|
2
|
+
require 'rcelery/task'
|
3
|
+
require 'rcelery/events'
|
4
|
+
require 'rcelery/worker'
|
5
|
+
require 'rcelery/configuration'
|
6
|
+
require 'rcelery/daemon'
|
7
|
+
require 'rcelery/task_support'
|
8
|
+
require 'rcelery/async_result'
|
9
|
+
require 'rcelery/eager_result'
|
10
|
+
require 'rcelery/version'
|
11
|
+
|
12
|
+
require 'rcelery/railtie' if defined?(Rails::Railtie)
|
13
|
+
|
14
|
+
module RCelery
|
15
|
+
@running = false
|
16
|
+
|
17
|
+
def self.start(config = {})
|
18
|
+
config = Configuration.new(config) if config.is_a?(Hash)
|
19
|
+
@config = config
|
20
|
+
|
21
|
+
@application = config.application
|
22
|
+
|
23
|
+
unless eager_mode?
|
24
|
+
if AMQP.connection.nil? || !AMQP.connection.connected?
|
25
|
+
@thread = Thread.new { AMQP.start(config.to_hash) }
|
26
|
+
end
|
27
|
+
|
28
|
+
channel = RCelery.channel
|
29
|
+
@exchanges = {
|
30
|
+
:request => channel.direct('celery', :durable => true),
|
31
|
+
:result => channel.direct('celeryresults', :durable => true, :auto_delete => true),
|
32
|
+
:event => channel.topic('celeryev', :durable => true)
|
33
|
+
}
|
34
|
+
@queue = channel.queue(RCelery.queue_name, :durable => true).bind(
|
35
|
+
exchanges[:request], :routing_key => RCelery.queue_name)
|
36
|
+
end
|
37
|
+
|
38
|
+
@running = true
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.stop
|
44
|
+
AMQP.stop { EM.stop } unless eager_mode?
|
45
|
+
@channel = nil
|
46
|
+
@running = false
|
47
|
+
@queue = nil
|
48
|
+
@exchanges = nil
|
49
|
+
@thread.kill unless eager_mode?
|
50
|
+
@thread = nil
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.channel
|
54
|
+
@channel ||= AMQP::Channel.new
|
55
|
+
end
|
56
|
+
|
57
|
+
def self.thread
|
58
|
+
@thread
|
59
|
+
end
|
60
|
+
|
61
|
+
def self.queue_name
|
62
|
+
"rcelery.#{@application}"
|
63
|
+
end
|
64
|
+
|
65
|
+
def self.running?
|
66
|
+
@running
|
67
|
+
end
|
68
|
+
|
69
|
+
def self.queue
|
70
|
+
@queue
|
71
|
+
end
|
72
|
+
|
73
|
+
def self.exchanges
|
74
|
+
@exchanges
|
75
|
+
end
|
76
|
+
|
77
|
+
def self.eager_mode?
|
78
|
+
@config.eager_mode if @config
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.publish(exchange, message, options = {})
|
82
|
+
options[:routing_key] ||= queue_name
|
83
|
+
options[:content_type] = 'application/json'
|
84
|
+
exchanges[exchange].publish(message.to_json, options)
|
85
|
+
end
|
86
|
+
end
|
data/rails/init.rb
ADDED
data/rcelery.gemspec
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
Gem::Specification.new do |s|
|
2
|
+
s.name = 'rcelery'
|
3
|
+
s.summary = 'Ruby implementation of the Python Celery library.'
|
4
|
+
s.version = '1.0.0'
|
5
|
+
|
6
|
+
ignore = ['.gitignore']
|
7
|
+
s.files = `git ls-files`.split("\n") - ignore
|
8
|
+
s.test_files = `git ls-files -- spec/*`.split("\n")
|
9
|
+
s.executables << 'rceleryd'
|
10
|
+
s.require_paths = ['lib']
|
11
|
+
|
12
|
+
s.authors = ['John MacKenzie', 'Kris Schultz', 'Nat Williams']
|
13
|
+
s.homepage = 'http://github.com'
|
14
|
+
s.email = 'oss@leapfrogdevelopment.com'
|
15
|
+
|
16
|
+
s.add_dependency('amqp', '~> 0.7.3')
|
17
|
+
s.add_dependency('uuid', '~> 2.0')
|
18
|
+
s.add_dependency('json', '~> 1.0')
|
19
|
+
s.add_dependency('configtoolkit', '~> 2.3')
|
20
|
+
s.add_dependency('qusion', '~> 0.1.9')
|
21
|
+
|
22
|
+
s.add_development_dependency('rspec', '~> 2.6')
|
23
|
+
s.add_development_dependency('rake', '~> 0.9.2')
|
24
|
+
s.add_development_dependency('rr', '~> 1.0')
|
25
|
+
s.add_development_dependency('SystemTimer', '~> 1.1')
|
26
|
+
s.add_development_dependency('foreman', '~> 0.20')
|
27
|
+
end
|
28
|
+
|
data/spec/bin/ci
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
#! /bin/bash
|
2
|
+
|
3
|
+
function install_gem_dependencies {
|
4
|
+
bundle install
|
5
|
+
}
|
6
|
+
|
7
|
+
function install_python_dependencies {
|
8
|
+
pushd spec/integration/python_components
|
9
|
+
virtualenv --no-site-packages .
|
10
|
+
bin/pip install -r requirements.txt
|
11
|
+
popd
|
12
|
+
}
|
13
|
+
|
14
|
+
function run_rabbit {
|
15
|
+
pushd spec/integration
|
16
|
+
bundle exec foreman start rabbit &
|
17
|
+
popd
|
18
|
+
|
19
|
+
export RABBITPID=$!
|
20
|
+
rabbitmqctl -q -n $RABBITMQ_NODENAME wait
|
21
|
+
rabbitmqctl -q -n $RABBITMQ_NODENAME add_vhost /integration
|
22
|
+
rabbitmqctl -q -n $RABBITMQ_NODENAME set_permissions -p /integration guest ".*" ".*" ".*"
|
23
|
+
}
|
24
|
+
|
25
|
+
function run_daemons {
|
26
|
+
pushd spec/integration
|
27
|
+
bundle exec foreman start -c 'rabbit=0,celeryd=1,rceleryd=1' &
|
28
|
+
popd
|
29
|
+
|
30
|
+
export DAEMONSPID=$!
|
31
|
+
}
|
32
|
+
|
33
|
+
function setup {
|
34
|
+
export RCELERY_PORT=${RCELERY_PORT:-5672}
|
35
|
+
export RCELERY_HOST=${RCELERY_HOST:-localhost}
|
36
|
+
export RCELERY_VHOST=${RCELERY_VHOST:-/integration}
|
37
|
+
export RABBITMQ_NODENAME=rcelery@localhost
|
38
|
+
export RABBITMQ_NODE_PORT=$RCELERY_PORT
|
39
|
+
export RABBITMQ_LOG_BASE=var/log
|
40
|
+
export RABBITMQ_MNESIA_BASE=var/mnesia
|
41
|
+
|
42
|
+
mkdir -p spec/integration/var/log
|
43
|
+
|
44
|
+
install_gem_dependencies
|
45
|
+
install_python_dependencies
|
46
|
+
# run_rabbit
|
47
|
+
run_daemons
|
48
|
+
}
|
49
|
+
|
50
|
+
function teardown {
|
51
|
+
# kill $RABBITPID
|
52
|
+
kill $DAEMONSPID
|
53
|
+
}
|
54
|
+
|
55
|
+
function break_on_fail {
|
56
|
+
if [ $? -ne 0 ]; then
|
57
|
+
teardown
|
58
|
+
exit 1
|
59
|
+
fi
|
60
|
+
}
|
61
|
+
|
62
|
+
function run_units {
|
63
|
+
bundle exec rake spec:unit
|
64
|
+
break_on_fail
|
65
|
+
}
|
66
|
+
|
67
|
+
function run_integrations {
|
68
|
+
export RCELERY_APPLICATION=integration
|
69
|
+
bundle exec rake spec:integration:ruby_worker
|
70
|
+
break_on_fail
|
71
|
+
|
72
|
+
export RCELERY_APPLICATION=python.integration
|
73
|
+
bundle exec rake spec:integration:python_worker
|
74
|
+
break_on_fail
|
75
|
+
}
|
76
|
+
|
77
|
+
setup
|
78
|
+
run_units
|
79
|
+
run_integrations
|
80
|
+
teardown
|
81
|
+
|
@@ -0,0 +1,26 @@
|
|
1
|
+
from os import environ
|
2
|
+
|
3
|
+
BROKER_HOST = environ.get('RCELERY_HOST', "localhost")
|
4
|
+
BROKER_PORT = environ.get('RCELERY_PORT', 5672)
|
5
|
+
BROKER_USER = environ.get('RCELERY_USERNAME', "guest")
|
6
|
+
BROKER_PASSWORD = environ.get('RCELERY_PASSWORD', "guest")
|
7
|
+
BROKER_VHOST = environ.get('RCELERY_VHOST', "/integration")
|
8
|
+
|
9
|
+
CELERY_RESULT_BACKEND = "amqp"
|
10
|
+
CELERY_RESULT_PERSISTENT = True
|
11
|
+
|
12
|
+
CELERY_QUEUES = {
|
13
|
+
"rcelery.integration": {"exchange": "celery",
|
14
|
+
"routing_key": "rcelery.integration"},
|
15
|
+
"rcelery.python.integration": {"exchange": "celery",
|
16
|
+
"routing_key": "rcelery.python.integration"}
|
17
|
+
}
|
18
|
+
|
19
|
+
CELERY_DEFAULT_QUEUE = "rcelery.integration"
|
20
|
+
|
21
|
+
CELERY_RESULT_SERIALIZER = "json"
|
22
|
+
CELERY_TASK_SERIALIZER = "json"
|
23
|
+
CELERY_AMQP_TASK_RESULT_EXPIRES = 3600
|
24
|
+
|
25
|
+
CELERY_IMPORTS = ("tasks", )
|
26
|
+
CELERY_SEND_EVENTS = True
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'integration/spec_helper'
|
2
|
+
require 'system_timer'
|
3
|
+
|
4
|
+
describe 'Ruby Client' do
|
5
|
+
include Tasks
|
6
|
+
|
7
|
+
it 'is able to talk to a python worker' do
|
8
|
+
result = add.delay(5,10)
|
9
|
+
result.wait.should == 15
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'can send tasks scheduled in the future to python workers' do
|
13
|
+
result = add.apply_async(:args => [5,3], :eta => Time.now + 5)
|
14
|
+
|
15
|
+
result.wait.should == 8
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,115 @@
|
|
1
|
+
require 'integration/spec_helper'
|
2
|
+
require 'system_timer'
|
3
|
+
|
4
|
+
describe 'Ruby Worker' do
|
5
|
+
include Tasks
|
6
|
+
|
7
|
+
it 'is able to consume messages posted by the ruby client' do
|
8
|
+
result = subtract.delay(16,9)
|
9
|
+
result.wait.should == 7
|
10
|
+
end
|
11
|
+
|
12
|
+
it 'is able to consume messages posted by the python client' do
|
13
|
+
result = `./spec/integration/python_components/bin/python ./spec/integration/python_components/celery_client.py`.to_i
|
14
|
+
result.should == 20
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'is able to consume messages with an eta from the python client' do
|
18
|
+
result = `./spec/integration/python_components/bin/python ./spec/integration/python_components/celery_deferred_client.py`.to_i
|
19
|
+
result.should == 25
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'will defer tasks scheduled for the future' do
|
23
|
+
sleep_result = sleeper.apply_async(:args => 5, :eta => Time.now + 5)
|
24
|
+
|
25
|
+
SystemTimer.timeout(4) do
|
26
|
+
result = subtract.delay(20, 1)
|
27
|
+
result.wait.should == 19
|
28
|
+
end
|
29
|
+
|
30
|
+
sleep_result.wait.should == 'FINISH'
|
31
|
+
end
|
32
|
+
|
33
|
+
it 'will retry a failed task' do
|
34
|
+
task_id = UUID.generate
|
35
|
+
stub(UUID).generate { task_id }
|
36
|
+
|
37
|
+
channel = RCelery.channel
|
38
|
+
event_queue = channel.queue('retries', :durable => true).bind(
|
39
|
+
RCelery.exchanges[:event], :routing_key => 'task.retried')
|
40
|
+
|
41
|
+
retries = 0
|
42
|
+
event_queue.subscribe do |header, payload|
|
43
|
+
event = JSON.parse(payload)
|
44
|
+
retries += 1 if event['uuid'] == task_id
|
45
|
+
end
|
46
|
+
|
47
|
+
result = retrier.delay(2)
|
48
|
+
|
49
|
+
result.wait.should == 'FINISH'
|
50
|
+
retries.should == 2
|
51
|
+
|
52
|
+
event_queue.unsubscribe
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'will not exceed the max retries (default 3)' do
|
56
|
+
task_id = UUID.generate
|
57
|
+
stub(UUID).generate { task_id }
|
58
|
+
|
59
|
+
channel = RCelery.channel
|
60
|
+
event_queue = channel.queue('failed_retries', :durable => true).bind(
|
61
|
+
RCelery.exchanges[:event], :routing_key => 'task.retried')
|
62
|
+
|
63
|
+
retries = 0
|
64
|
+
event_queue.subscribe do |header, payload|
|
65
|
+
event = JSON.parse(payload)
|
66
|
+
retries += 1 if event['uuid'] == task_id
|
67
|
+
end
|
68
|
+
|
69
|
+
result = retrier.delay(4)
|
70
|
+
|
71
|
+
result.wait.should =~ /MaxRetriesExceeded/
|
72
|
+
retries.should == 3
|
73
|
+
|
74
|
+
event_queue.unsubscribe
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'is able to concurrently process tasks' do
|
78
|
+
sleep_result = sleeper.delay(5)
|
79
|
+
sleep(1)
|
80
|
+
|
81
|
+
SystemTimer.timeout(3) do
|
82
|
+
subtract_result = subtract.delay(20,1)
|
83
|
+
subtract_result.wait.should == 19
|
84
|
+
end
|
85
|
+
|
86
|
+
sleep_result.wait.should == "FINISH"
|
87
|
+
end
|
88
|
+
|
89
|
+
it 'is able to concurrently process many of the same task' do
|
90
|
+
add_result1 = add.delay(5,5)
|
91
|
+
add_result2 = add.delay(6,7)
|
92
|
+
add_result3 = add.delay(7,9)
|
93
|
+
|
94
|
+
add_result1.wait.should == 10
|
95
|
+
add_result2.wait.should == 13
|
96
|
+
add_result3.wait.should == 16
|
97
|
+
end
|
98
|
+
|
99
|
+
it 'is able to concurrently retry many of the same task' do
|
100
|
+
result1 = noop_retry.delay(1)
|
101
|
+
result2 = noop_retry.delay(2)
|
102
|
+
result3 = noop_retry.delay(3)
|
103
|
+
result4 = noop_retry.delay(4)
|
104
|
+
result5 = noop_retry.delay(5)
|
105
|
+
result6 = noop_retry.delay(6)
|
106
|
+
|
107
|
+
result1.wait.should == 1
|
108
|
+
result2.wait.should == 2
|
109
|
+
result3.wait.should == 3
|
110
|
+
result4.wait.should == 4
|
111
|
+
result5.wait.should == 5
|
112
|
+
result6.wait.should == 6
|
113
|
+
end
|
114
|
+
end
|
115
|
+
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
|
4
|
+
Bundler.setup
|
5
|
+
|
6
|
+
require 'rspec'
|
7
|
+
require 'rcelery'
|
8
|
+
require 'spec/integration/tasks'
|
9
|
+
require 'timeout'
|
10
|
+
|
11
|
+
|
12
|
+
module Support
|
13
|
+
def self.config
|
14
|
+
{
|
15
|
+
:application => ENV['RCELERY_APPLICATION'] || 'integration',
|
16
|
+
:host => ENV['RCELERY_HOST'] || 'localhost',
|
17
|
+
:port => ENV['RCELERY_PORT'] || 5672,
|
18
|
+
:vhost => ENV['RCELERY_VHOST'] || '/integration',
|
19
|
+
:username => ENV['RCELERY_USERNAME'] || 'guest',
|
20
|
+
:password => ENV['RCELERY_PASSWORD'] || 'guest',
|
21
|
+
:worker_count => ENV['RCELERY_WORKERS'] || 2
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
RSpec.configure do |config|
|
27
|
+
config.mock_with :rr
|
28
|
+
|
29
|
+
config.before :all do
|
30
|
+
RCelery.start(Support.config)
|
31
|
+
end
|
32
|
+
|
33
|
+
config.after :each do
|
34
|
+
RCelery.queue.purge()
|
35
|
+
end
|
36
|
+
|
37
|
+
config.around :each do |example|
|
38
|
+
Timeout.timeout(15) do
|
39
|
+
example.run
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Tasks
|
2
|
+
include RCelery::TaskSupport
|
3
|
+
|
4
|
+
task(:name => 'r_celery.integration.subtract', :ignore_result => false)
|
5
|
+
def subtract(a,b)
|
6
|
+
a - b
|
7
|
+
end
|
8
|
+
|
9
|
+
task(:name => 'r_celery.integration.multiply', :ignore_result => false)
|
10
|
+
def multiply(a,b)
|
11
|
+
a * b
|
12
|
+
end
|
13
|
+
|
14
|
+
task(:name => 'r_celery.integration.add', :ignore_result => false)
|
15
|
+
def add(a,b)
|
16
|
+
a + b
|
17
|
+
end
|
18
|
+
|
19
|
+
task(:name => 'r_celery.integration.sleep', :ignore_result => false)
|
20
|
+
def sleeper(t)
|
21
|
+
sleep(t.to_i)
|
22
|
+
'FINISH'
|
23
|
+
end
|
24
|
+
|
25
|
+
task(:name => 'r_celery.integration.retry', :ignore_result => false)
|
26
|
+
def retrier(retries = 0)
|
27
|
+
retrier.retry(:args => [retries-1], :eta => Time.now) unless retries.zero?
|
28
|
+
'FINISH'
|
29
|
+
end
|
30
|
+
|
31
|
+
task(:name => 'r_celery.integration.noop_retry', :ignore_result => false)
|
32
|
+
def noop_retry(a)
|
33
|
+
noop_retry.retry(:eta => Time.now)
|
34
|
+
rescue RCelery::Task::MaxRetriesExceededError
|
35
|
+
a
|
36
|
+
end
|
37
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
|
4
|
+
Bundler.setup
|
5
|
+
|
6
|
+
require 'rspec'
|
7
|
+
require 'rcelery'
|
8
|
+
|
9
|
+
module AMQPMock
|
10
|
+
def stub_amqp
|
11
|
+
queue = stub!.bind { queue }.subject
|
12
|
+
stub(queue).subscribe { queue }
|
13
|
+
stub(queue).unsubscribe { queue }
|
14
|
+
channel = stub!.direct.subject
|
15
|
+
stub(channel).topic
|
16
|
+
stub(channel).queue { queue }
|
17
|
+
|
18
|
+
stub(RCelery).channel{ channel }
|
19
|
+
|
20
|
+
[channel, queue]
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
RSpec.configure do |config|
|
25
|
+
config.mock_with :rr
|
26
|
+
|
27
|
+
config.before :all do
|
28
|
+
stub(AMQP).start
|
29
|
+
stub(AMQP).stop
|
30
|
+
end
|
31
|
+
|
32
|
+
config.include AMQPMock
|
33
|
+
end
|
34
|
+
|