chore-core 1.10.0 → 4.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.
- checksums.yaml +5 -13
- data/LICENSE.txt +1 -1
- data/README.md +172 -153
- data/chore-core.gemspec +3 -3
- data/lib/chore.rb +29 -5
- data/lib/chore/cli.rb +22 -4
- data/lib/chore/configuration.rb +1 -1
- data/lib/chore/consumer.rb +54 -12
- data/lib/chore/fetcher.rb +12 -7
- data/lib/chore/hooks.rb +2 -1
- data/lib/chore/job.rb +19 -0
- data/lib/chore/manager.rb +17 -2
- data/lib/chore/publisher.rb +18 -2
- data/lib/chore/queues/filesystem/consumer.rb +126 -64
- data/lib/chore/queues/filesystem/filesystem_queue.rb +19 -0
- data/lib/chore/queues/filesystem/publisher.rb +10 -16
- data/lib/chore/queues/sqs.rb +22 -13
- data/lib/chore/queues/sqs/consumer.rb +64 -51
- data/lib/chore/queues/sqs/publisher.rb +26 -17
- data/lib/chore/strategies/consumer/batcher.rb +6 -6
- data/lib/chore/strategies/consumer/single_consumer_strategy.rb +5 -5
- data/lib/chore/strategies/consumer/threaded_consumer_strategy.rb +7 -6
- data/lib/chore/strategies/consumer/throttled_consumer_strategy.rb +120 -0
- data/lib/chore/strategies/worker/forked_worker_strategy.rb +5 -6
- data/lib/chore/strategies/worker/helpers/ipc.rb +87 -0
- data/lib/chore/strategies/worker/helpers/preforked_worker.rb +163 -0
- data/lib/chore/strategies/worker/helpers/work_distributor.rb +65 -0
- data/lib/chore/strategies/worker/helpers/worker_info.rb +13 -0
- data/lib/chore/strategies/worker/helpers/worker_killer.rb +40 -0
- data/lib/chore/strategies/worker/helpers/worker_manager.rb +183 -0
- data/lib/chore/strategies/worker/preforked_worker_strategy.rb +150 -0
- data/lib/chore/unit_of_work.rb +2 -1
- data/lib/chore/util.rb +5 -1
- data/lib/chore/version.rb +2 -2
- data/lib/chore/worker.rb +30 -3
- data/spec/chore/cli_spec.rb +2 -2
- data/spec/chore/consumer_spec.rb +1 -5
- data/spec/chore/duplicate_detector_spec.rb +17 -5
- data/spec/chore/fetcher_spec.rb +0 -11
- data/spec/chore/manager_spec.rb +7 -0
- data/spec/chore/queues/filesystem/filesystem_consumer_spec.rb +74 -16
- data/spec/chore/queues/sqs/consumer_spec.rb +117 -78
- data/spec/chore/queues/sqs/publisher_spec.rb +49 -60
- data/spec/chore/queues/sqs_spec.rb +32 -41
- data/spec/chore/strategies/consumer/single_consumer_strategy_spec.rb +3 -3
- data/spec/chore/strategies/consumer/threaded_consumer_strategy_spec.rb +6 -6
- data/spec/chore/strategies/consumer/throttled_consumer_strategy_spec.rb +165 -0
- data/spec/chore/strategies/worker/forked_worker_strategy_spec.rb +6 -1
- data/spec/chore/strategies/worker/helpers/ipc_spec.rb +127 -0
- data/spec/chore/strategies/worker/helpers/preforked_worker_spec.rb +236 -0
- data/spec/chore/strategies/worker/helpers/work_distributor_spec.rb +131 -0
- data/spec/chore/strategies/worker/helpers/worker_info_spec.rb +14 -0
- data/spec/chore/strategies/worker/helpers/worker_killer_spec.rb +97 -0
- data/spec/chore/strategies/worker/helpers/worker_manager_spec.rb +304 -0
- data/spec/chore/strategies/worker/preforked_worker_strategy_spec.rb +183 -0
- data/spec/chore/strategies/worker/single_worker_strategy_spec.rb +1 -1
- data/spec/chore/worker_spec.rb +70 -15
- data/spec/spec_helper.rb +1 -1
- data/spec/support/queues/sqs/fake_objects.rb +18 -0
- metadata +53 -29
@@ -1,74 +1,63 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
let(:job) { {'class' => 'TestJob', 'args'=>[1,2,'3']}}
|
6
|
-
let(:queue_name) { 'test_queue' }
|
7
|
-
let(:queue_url) {"http://www.queue_url.com/test_queue"}
|
8
|
-
let(:queue) { double('queue', :send_message => nil) }
|
9
|
-
let(:sqs) do
|
10
|
-
double('sqs', :queues => double('queues', :named => queue, :url_for => queue_url, :[] => queue))
|
11
|
-
end
|
12
|
-
let(:publisher) { Queues::SQS::Publisher.new }
|
13
|
-
let(:pool) { double("pool") }
|
3
|
+
describe Chore::Queues::SQS::Publisher do
|
4
|
+
include_context 'fake objects'
|
14
5
|
|
15
|
-
|
16
|
-
|
17
|
-
|
6
|
+
let(:publisher) { Chore::Queues::SQS::Publisher.new }
|
7
|
+
let(:job) { {'class' => 'TestJob', 'args'=>[1,2,'3']}}
|
8
|
+
let(:send_message_result) { double(Aws::SQS::Types::SendMessageResult, :data => job) }
|
18
9
|
|
19
|
-
|
20
|
-
|
21
|
-
|
10
|
+
before(:each) do
|
11
|
+
allow(Aws::SQS::Client).to receive(:new).and_return(sqs)
|
12
|
+
allow(sqs).to receive(:send_message).and_return(send_message_result)
|
13
|
+
end
|
22
14
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
:log_level => :debug
|
28
|
-
)
|
29
|
-
publisher.publish(queue_name,job)
|
30
|
-
end
|
15
|
+
it 'should configure sqs' do
|
16
|
+
expect(Aws::SQS::Client).to receive(:new)
|
17
|
+
publisher.publish(queue_name,job)
|
18
|
+
end
|
31
19
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
20
|
+
it 'should not create a new SQS client before every publish' do
|
21
|
+
expect(Aws::SQS::Client).to receive(:new).once
|
22
|
+
2.times { publisher.send(:queue, queue_name) }
|
23
|
+
end
|
36
24
|
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
25
|
+
it 'should lookup the queue when publishing' do
|
26
|
+
expect(sqs).to receive(:get_queue_url).with(queue_name: queue_name)
|
27
|
+
publisher.publish(queue_name, job)
|
28
|
+
end
|
41
29
|
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
30
|
+
it 'should create send an encoded message to the specified queue' do
|
31
|
+
expect(sqs).to receive(:send_message).with(queue_url: queue_url, message_body: job.to_json)
|
32
|
+
publisher.publish(queue_name,job)
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should lookup multiple queues if specified' do
|
36
|
+
second_queue_name = queue_name + '2'
|
37
|
+
expect(sqs).to receive(:get_queue_url).with(queue_name: queue_name)
|
38
|
+
expect(sqs).to receive(:get_queue_url).with(queue_name: second_queue_name)
|
39
|
+
|
40
|
+
publisher.publish(queue_name, job)
|
41
|
+
publisher.publish(second_queue_name, job)
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should only lookup a named queue once' do
|
45
|
+
expect(sqs).to receive(:get_queue_url).with(queue_name: queue_name).once
|
46
|
+
4.times { publisher.publish(queue_name, job) }
|
47
|
+
end
|
48
48
|
|
49
|
-
|
50
|
-
|
51
|
-
|
49
|
+
describe '#reset_connection!' do
|
50
|
+
it 'should empty API client connection pool after a call to reset_connection!' do
|
51
|
+
expect(Aws).to receive(:empty_connection_pools!)
|
52
|
+
Chore::Queues::SQS::Publisher.reset_connection!
|
53
|
+
publisher.send(:queue, queue_name)
|
52
54
|
end
|
53
55
|
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
publisher.queue(queue_name)
|
60
|
-
end
|
61
|
-
|
62
|
-
it 'should not reset the connection between calls' do
|
63
|
-
sqs = publisher.queue(queue_name)
|
64
|
-
sqs.should be publisher.queue(queue_name)
|
65
|
-
end
|
66
|
-
|
67
|
-
it 'should reconfigure sqs' do
|
68
|
-
Chore::Queues::SQS::Publisher.reset_connection!
|
69
|
-
AWS::SQS.should_receive(:new)
|
70
|
-
publisher.queue(queue_name)
|
71
|
-
end
|
56
|
+
# TODO: this test seems like basic identity (i.e. not even a real test)
|
57
|
+
it 'should not reset the connection between calls' do
|
58
|
+
expect(Aws).to receive(:empty_connection_pools!).once
|
59
|
+
Chore::Queues::SQS::Publisher.reset_connection!
|
60
|
+
4.times { publisher.send(:queue, queue_name ) }
|
72
61
|
end
|
73
62
|
end
|
74
63
|
end
|
@@ -1,53 +1,44 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
allow(fake_queue).to receive(:delete)
|
3
|
+
describe Chore::Queues::SQS do
|
4
|
+
include_context 'fake objects'
|
5
|
+
|
6
|
+
context "when managing queues" do
|
7
|
+
before(:each) do
|
8
|
+
allow(Aws::SQS::Client).to receive(:new).and_return(sqs)
|
9
|
+
allow(sqs).to receive(:create_queue).and_return(queue)
|
10
|
+
allow(sqs).to receive(:delete_queue).and_return(Struct.new(nil))
|
11
|
+
allow(queue).to receive(:delete).and_return(sqs.delete_queue(queue))
|
12
|
+
allow(Chore).to receive(:prefixed_queue_names).and_return([queue_name])
|
13
|
+
allow(queue).to receive(:delete)
|
14
|
+
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
it 'should create queues that are defined in its internal job name list' do
|
17
|
+
#Only one job defined in the spec suite
|
18
|
+
expect(sqs).to receive(:create_queue).with(queue_name: queue_name)
|
19
|
+
Chore::Queues::SQS.create_queues!
|
20
|
+
end
|
20
21
|
|
21
|
-
|
22
|
-
|
22
|
+
it 'should delete queues that are defined in its internal job name list' do
|
23
|
+
#Only one job defined in the spec suite
|
24
|
+
expect(sqs).to receive(:delete_queue).with(queue_url: sqs.get_queue_url.queue_url)
|
25
|
+
Chore::Queues::SQS.delete_queues!
|
26
|
+
end
|
23
27
|
|
24
|
-
|
25
|
-
|
26
|
-
expect(
|
27
|
-
Chore::Queues::SQS.create_queues!
|
28
|
+
context 'and checking for existing queues' do
|
29
|
+
it 'checks for existing queues' do
|
30
|
+
expect(described_class).to receive(:existing_queues).and_return([])
|
31
|
+
Chore::Queues::SQS.create_queues!(true)
|
28
32
|
end
|
29
33
|
|
30
|
-
it '
|
31
|
-
|
32
|
-
expect(
|
33
|
-
Chore::Queues::SQS.delete_queues!
|
34
|
+
it 'raises an error if a queue does exist' do
|
35
|
+
allow(described_class).to receive(:existing_queues).and_return([queue_name])
|
36
|
+
expect{Chore::Queues::SQS.create_queues!(true)}.to raise_error(RuntimeError)
|
34
37
|
end
|
35
38
|
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
Chore::Queues::SQS.create_queues!(true)
|
40
|
-
end
|
41
|
-
|
42
|
-
it 'raises an error if a queue does exist' do
|
43
|
-
allow(described_class).to receive(:existing_queues).and_return([queue_name])
|
44
|
-
expect{Chore::Queues::SQS.create_queues!(true)}.to raise_error(RuntimeError)
|
45
|
-
end
|
46
|
-
|
47
|
-
it 'does not raise an error if a queue does not exist' do
|
48
|
-
allow(described_class).to receive(:existing_queues).and_return([])
|
49
|
-
expect{Chore::Queues::SQS.create_queues!(true)}.not_to raise_error
|
50
|
-
end
|
39
|
+
it 'does not raise an error if a queue does not exist' do
|
40
|
+
allow(described_class).to receive(:existing_queues).and_return([])
|
41
|
+
expect{Chore::Queues::SQS.create_queues!(true)}.not_to raise_error
|
51
42
|
end
|
52
43
|
end
|
53
44
|
end
|
@@ -11,13 +11,13 @@ describe Chore::Strategy::SingleConsumerStrategy do
|
|
11
11
|
fetcher.stub(:manager) { manager }
|
12
12
|
Chore.config.stub(:queues).and_return(test_queues)
|
13
13
|
Chore.config.stub(:consumer).and_return(consumer)
|
14
|
-
|
14
|
+
|
15
15
|
end
|
16
16
|
|
17
17
|
it "should consume and then assign a message" do
|
18
18
|
consumer.should_receive(:new).with(test_queues.first).and_return(consumer)
|
19
|
-
consumer.should_receive(:consume).and_yield(1, 'test-queue', 60, "test", 0)
|
20
|
-
manager.should_receive(:assign).with(Chore::UnitOfWork.new(1, 'test-queue', 60, "test", 0, consumer))
|
19
|
+
consumer.should_receive(:consume).and_yield(1, nil, 'test-queue', 60, "test", 0)
|
20
|
+
manager.should_receive(:assign).with(Chore::UnitOfWork.new(1, nil, 'test-queue', 60, "test", 0, consumer))
|
21
21
|
strategy.fetch
|
22
22
|
end
|
23
23
|
end
|
@@ -29,8 +29,8 @@ describe Chore::Strategy::ThreadedConsumerStrategy do
|
|
29
29
|
before(:each) do
|
30
30
|
fetcher.stub(:consumers) { [consumer] }
|
31
31
|
fetcher.stub(:manager) { manager }
|
32
|
-
Chore.configure do |c|
|
33
|
-
c.queues = ['test']
|
32
|
+
Chore.configure do |c|
|
33
|
+
c.queues = ['test']
|
34
34
|
c.consumer = consumer
|
35
35
|
c.batch_size = batch_size
|
36
36
|
end
|
@@ -40,7 +40,7 @@ describe Chore::Strategy::ThreadedConsumerStrategy do
|
|
40
40
|
let(:batch_size) { 2 }
|
41
41
|
|
42
42
|
it "should queue but not assign the message" do
|
43
|
-
consumer.any_instance.should_receive(:consume).and_yield(1, 'test-queue', 60, "test", 0)
|
43
|
+
consumer.any_instance.should_receive(:consume).and_yield(1, nil, 'test-queue', 60, "test", 0)
|
44
44
|
strategy.fetch
|
45
45
|
strategy.batcher.batch.size.should == 1
|
46
46
|
|
@@ -60,7 +60,7 @@ describe Chore::Strategy::ThreadedConsumerStrategy do
|
|
60
60
|
|
61
61
|
it "should assign the batch" do
|
62
62
|
manager.should_receive(:assign)
|
63
|
-
consumer.any_instance.should_receive(:consume).and_yield(1, 'test-queue', 60, "test", 0)
|
63
|
+
consumer.any_instance.should_receive(:consume).and_yield(1, nil, 'test-queue', 60, "test", 0)
|
64
64
|
strategy.fetch
|
65
65
|
strategy.batcher.batch.size.should == 0
|
66
66
|
end
|
@@ -90,8 +90,8 @@ describe Chore::Strategy::ThreadedConsumerStrategy do
|
|
90
90
|
|
91
91
|
before do
|
92
92
|
fetcher.stub(:consumers) { [bad_consumer] }
|
93
|
-
Chore.configure do |c|
|
94
|
-
c.queues = ['test']
|
93
|
+
Chore.configure do |c|
|
94
|
+
c.queues = ['test']
|
95
95
|
c.consumer = bad_consumer
|
96
96
|
c.batch_size = batch_size
|
97
97
|
c.threads_per_queue = 1
|
@@ -0,0 +1,165 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
class TestConsumer < Chore::Consumer
|
4
|
+
def initialize(queue_name, opts={})
|
5
|
+
end
|
6
|
+
|
7
|
+
def consume
|
8
|
+
# just something that looks like an SQS message
|
9
|
+
msg = OpenStruct.new( :id => 1, :body => "test" )
|
10
|
+
yield msg if block_given?
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class NoQueueConsumer < Chore::Consumer
|
15
|
+
def initialize(queue_name, opts={})
|
16
|
+
raise Chore::TerribleMistake
|
17
|
+
end
|
18
|
+
|
19
|
+
def consume
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
describe Chore::Strategy::ThrottledConsumerStrategy do
|
24
|
+
let(:fetcher) { double("fetcher") }
|
25
|
+
let(:manager) { double("manager") }
|
26
|
+
let(:thread) {double("thread")}
|
27
|
+
let(:consume_queue) { "TestQueue" }
|
28
|
+
let(:consumer) { TestConsumer }
|
29
|
+
let(:consumer_object) { consumer.new(consume_queue) }
|
30
|
+
let(:strategy) { Chore::Strategy::ThrottledConsumerStrategy.new(fetcher) }
|
31
|
+
let(:config) { double("config") }
|
32
|
+
let(:sized_queue) {double("sized_queue")}
|
33
|
+
let(:return_queue) {double("return_queue")}
|
34
|
+
let(:work) { double("work") }
|
35
|
+
let(:msg) { OpenStruct.new( :id => 1, :body => "test" ) }
|
36
|
+
|
37
|
+
|
38
|
+
before(:each) do
|
39
|
+
allow(fetcher).to receive(:consumers).and_return([consumer])
|
40
|
+
allow(fetcher).to receive(:manager).and_return(manager)
|
41
|
+
Chore.configure do |c|
|
42
|
+
c.queues = [consume_queue]
|
43
|
+
c.consumer = consumer
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context '#fetch' do
|
48
|
+
it 'should call consume, \'@number_of_consumers\' number of times' do
|
49
|
+
allow(strategy).to receive(:consume).and_return(thread)
|
50
|
+
allow(thread).to receive(:join).and_return(true)
|
51
|
+
allow(Chore).to receive(:config).and_return(config)
|
52
|
+
allow(config).to receive(:queues).and_return([consume_queue])
|
53
|
+
strategy.instance_variable_set(:@consumers_per_queue, 5)
|
54
|
+
expect(strategy).to receive(:consume).with(consume_queue).exactly(5).times
|
55
|
+
strategy.fetch
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
context '#stop!' do
|
60
|
+
it 'should should stop itself, and every other consumer' do
|
61
|
+
allow(strategy).to receive(:running?).and_return(true)
|
62
|
+
strategy.instance_eval('@running = true')
|
63
|
+
strategy.instance_variable_set(:@consumers, [consumer_object])
|
64
|
+
expect(consumer_object).to receive(:stop)
|
65
|
+
strategy.stop!
|
66
|
+
expect(strategy.instance_variable_get(:@running)).to eq(false)
|
67
|
+
end
|
68
|
+
end
|
69
|
+
|
70
|
+
context '#provide_work' do
|
71
|
+
it 'should return upto n units of work' do
|
72
|
+
n = 2
|
73
|
+
strategy.instance_variable_set(:@queue, sized_queue)
|
74
|
+
allow(sized_queue).to receive(:size).and_return(10)
|
75
|
+
allow(sized_queue).to receive(:pop).and_return(work)
|
76
|
+
expect(sized_queue).to receive(:pop).exactly(n).times
|
77
|
+
res = strategy.provide_work(n)
|
78
|
+
expect(res.size).to eq(n)
|
79
|
+
expect(res).to be_a_kind_of(Array)
|
80
|
+
end
|
81
|
+
|
82
|
+
it 'should return an empty array if no work is found in the queue' do
|
83
|
+
n = 2
|
84
|
+
strategy.instance_variable_set(:@queue, sized_queue)
|
85
|
+
allow(sized_queue).to receive(:size).and_return(0)
|
86
|
+
allow(sized_queue).to receive(:pop).and_return(work)
|
87
|
+
expect(sized_queue).to receive(:pop).exactly(0).times
|
88
|
+
res = strategy.provide_work(n)
|
89
|
+
expect(res.size).to eq(0)
|
90
|
+
expect(res).to be_a_kind_of(Array)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should return units of work from the return queue first' do
|
94
|
+
n = 2
|
95
|
+
strategy.instance_variable_set(:@return_queue, return_queue)
|
96
|
+
allow(return_queue).to receive(:empty?).and_return(false)
|
97
|
+
allow(return_queue).to receive(:size).and_return(10)
|
98
|
+
allow(return_queue).to receive(:pop).and_return(work)
|
99
|
+
expect(return_queue).to receive(:pop).exactly(n).times
|
100
|
+
res = strategy.provide_work(n)
|
101
|
+
expect(res.size).to eq(n)
|
102
|
+
expect(res).to be_a_kind_of(Array)
|
103
|
+
end
|
104
|
+
|
105
|
+
it 'should return units of work from all queues if return queue is small' do
|
106
|
+
n = 2
|
107
|
+
|
108
|
+
strategy.instance_variable_set(:@return_queue, return_queue)
|
109
|
+
allow(return_queue).to receive(:empty?).and_return(false, true)
|
110
|
+
allow(return_queue).to receive(:size).and_return(1)
|
111
|
+
allow(return_queue).to receive(:pop).and_return(work)
|
112
|
+
expect(return_queue).to receive(:pop).once
|
113
|
+
|
114
|
+
strategy.instance_variable_set(:@queue, sized_queue)
|
115
|
+
allow(sized_queue).to receive(:size).and_return(1)
|
116
|
+
allow(sized_queue).to receive(:pop).and_return(work)
|
117
|
+
expect(sized_queue).to receive(:pop).once
|
118
|
+
|
119
|
+
res = strategy.provide_work(n)
|
120
|
+
expect(res.size).to eq(n)
|
121
|
+
expect(res).to be_a_kind_of(Array)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
context 'return_work' do
|
126
|
+
it 'should add it to the internal return queue' do
|
127
|
+
strategy.instance_variable_set(:@return_queue, [])
|
128
|
+
strategy.send(:return_work, [work])
|
129
|
+
strategy.send(:return_work, [work])
|
130
|
+
return_queue = strategy.instance_variable_get(:@return_queue)
|
131
|
+
expect(return_queue).to eq([work, work])
|
132
|
+
end
|
133
|
+
end
|
134
|
+
|
135
|
+
context '#consume' do
|
136
|
+
it 'should create a consumer object, add it to the list of consumers and start a consumer thread' do
|
137
|
+
allow(strategy).to receive(:start_consumer_thread).and_return(true)
|
138
|
+
expect(strategy).to receive(:start_consumer_thread)
|
139
|
+
strategy.send(:consume, consume_queue)
|
140
|
+
expect(strategy.instance_variable_get(:@consumers)).to be_a_kind_of(Array)
|
141
|
+
expect(strategy.instance_variable_get(:@consumers).first).to be_a_kind_of(TestConsumer)
|
142
|
+
end
|
143
|
+
end
|
144
|
+
|
145
|
+
context '#start_consumer_thread' do
|
146
|
+
let(:thread) { double('thread') }
|
147
|
+
|
148
|
+
it 'should create a thread' do
|
149
|
+
allow(Thread).to receive(:new).and_return(thread)
|
150
|
+
res = strategy.send(:start_consumer_thread, consumer_object)
|
151
|
+
expect(res).to eq(thread)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
context '#create_work_units' do
|
156
|
+
it 'should create an unit of work from what the consumer gets, and adds it to the internal queue' do
|
157
|
+
strategy.instance_variable_set(:@queue, [])
|
158
|
+
res = strategy.send(:create_work_units, consumer_object)
|
159
|
+
internal_queue = strategy.instance_variable_get(:@queue)
|
160
|
+
expect(internal_queue).to be_a_kind_of(Array)
|
161
|
+
expect(internal_queue.first).to be_a_kind_of(Chore::UnitOfWork)
|
162
|
+
expect(internal_queue.first.id).to eq(msg)
|
163
|
+
end
|
164
|
+
end
|
165
|
+
end
|
@@ -13,6 +13,7 @@ describe Chore::Strategy::ForkedWorkerStrategy do
|
|
13
13
|
let(:job) do
|
14
14
|
Chore::UnitOfWork.new(
|
15
15
|
SecureRandom.uuid,
|
16
|
+
nil,
|
16
17
|
'test',
|
17
18
|
job_timeout,
|
18
19
|
Chore::Encoder::JsonEncoder.encode(TestJob.job_hash([1,2,"3"])),
|
@@ -23,6 +24,10 @@ describe Chore::Strategy::ForkedWorkerStrategy do
|
|
23
24
|
let!(:worker) { Chore::Worker.new(job) }
|
24
25
|
let(:pid) { Random.rand(2048) }
|
25
26
|
|
27
|
+
before(:each) do
|
28
|
+
allow(consumer).to receive(:duplicate_message?).and_return(false)
|
29
|
+
end
|
30
|
+
|
26
31
|
after(:each) do
|
27
32
|
allow(Process).to receive(:kill) { nil }
|
28
33
|
allow(Process).to receive(:wait) { pid }
|
@@ -174,6 +179,7 @@ describe Chore::Strategy::ForkedWorkerStrategy do
|
|
174
179
|
end
|
175
180
|
|
176
181
|
it 'should run the on_failure callback hook' do
|
182
|
+
allow(Chore).to receive(:run_hooks_for)
|
177
183
|
forker.assign(job)
|
178
184
|
expect(Chore).to receive(:run_hooks_for).with(:on_failure, anything, instance_of(Chore::TimeoutError))
|
179
185
|
sleep 2
|
@@ -291,4 +297,3 @@ describe Chore::Strategy::ForkedWorkerStrategy do
|
|
291
297
|
end
|
292
298
|
end
|
293
299
|
end
|
294
|
-
|