chore-core 1.8.2 → 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.
Files changed (62) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +173 -150
  4. data/chore-core.gemspec +3 -3
  5. data/lib/chore.rb +31 -5
  6. data/lib/chore/cli.rb +22 -4
  7. data/lib/chore/configuration.rb +1 -1
  8. data/lib/chore/consumer.rb +54 -12
  9. data/lib/chore/fetcher.rb +12 -7
  10. data/lib/chore/hooks.rb +2 -1
  11. data/lib/chore/job.rb +19 -0
  12. data/lib/chore/manager.rb +18 -2
  13. data/lib/chore/publisher.rb +18 -2
  14. data/lib/chore/queues/filesystem/consumer.rb +126 -64
  15. data/lib/chore/queues/filesystem/filesystem_queue.rb +19 -0
  16. data/lib/chore/queues/filesystem/publisher.rb +13 -19
  17. data/lib/chore/queues/sqs.rb +22 -13
  18. data/lib/chore/queues/sqs/consumer.rb +64 -51
  19. data/lib/chore/queues/sqs/publisher.rb +26 -17
  20. data/lib/chore/strategies/consumer/batcher.rb +14 -15
  21. data/lib/chore/strategies/consumer/single_consumer_strategy.rb +5 -5
  22. data/lib/chore/strategies/consumer/threaded_consumer_strategy.rb +9 -7
  23. data/lib/chore/strategies/consumer/throttled_consumer_strategy.rb +120 -0
  24. data/lib/chore/strategies/worker/forked_worker_strategy.rb +5 -6
  25. data/lib/chore/strategies/worker/helpers/ipc.rb +87 -0
  26. data/lib/chore/strategies/worker/helpers/preforked_worker.rb +163 -0
  27. data/lib/chore/strategies/worker/helpers/work_distributor.rb +65 -0
  28. data/lib/chore/strategies/worker/helpers/worker_info.rb +13 -0
  29. data/lib/chore/strategies/worker/helpers/worker_killer.rb +40 -0
  30. data/lib/chore/strategies/worker/helpers/worker_manager.rb +183 -0
  31. data/lib/chore/strategies/worker/preforked_worker_strategy.rb +150 -0
  32. data/lib/chore/strategies/worker/single_worker_strategy.rb +35 -13
  33. data/lib/chore/unit_of_work.rb +10 -1
  34. data/lib/chore/util.rb +5 -1
  35. data/lib/chore/version.rb +3 -3
  36. data/lib/chore/worker.rb +32 -3
  37. data/spec/chore/cli_spec.rb +2 -2
  38. data/spec/chore/consumer_spec.rb +1 -5
  39. data/spec/chore/duplicate_detector_spec.rb +17 -5
  40. data/spec/chore/fetcher_spec.rb +0 -11
  41. data/spec/chore/manager_spec.rb +7 -0
  42. data/spec/chore/queues/filesystem/filesystem_consumer_spec.rb +74 -16
  43. data/spec/chore/queues/sqs/consumer_spec.rb +117 -78
  44. data/spec/chore/queues/sqs/publisher_spec.rb +49 -60
  45. data/spec/chore/queues/sqs_spec.rb +32 -41
  46. data/spec/chore/strategies/consumer/batcher_spec.rb +50 -0
  47. data/spec/chore/strategies/consumer/single_consumer_strategy_spec.rb +3 -3
  48. data/spec/chore/strategies/consumer/threaded_consumer_strategy_spec.rb +7 -6
  49. data/spec/chore/strategies/consumer/throttled_consumer_strategy_spec.rb +165 -0
  50. data/spec/chore/strategies/worker/forked_worker_strategy_spec.rb +17 -2
  51. data/spec/chore/strategies/worker/helpers/ipc_spec.rb +127 -0
  52. data/spec/chore/strategies/worker/helpers/preforked_worker_spec.rb +236 -0
  53. data/spec/chore/strategies/worker/helpers/work_distributor_spec.rb +131 -0
  54. data/spec/chore/strategies/worker/helpers/worker_info_spec.rb +14 -0
  55. data/spec/chore/strategies/worker/helpers/worker_killer_spec.rb +97 -0
  56. data/spec/chore/strategies/worker/helpers/worker_manager_spec.rb +304 -0
  57. data/spec/chore/strategies/worker/preforked_worker_strategy_spec.rb +183 -0
  58. data/spec/chore/strategies/worker/single_worker_strategy_spec.rb +25 -0
  59. data/spec/chore/worker_spec.rb +82 -14
  60. data/spec/spec_helper.rb +1 -1
  61. data/spec/support/queues/sqs/fake_objects.rb +18 -0
  62. metadata +39 -15
@@ -2,6 +2,8 @@ require 'spec_helper'
2
2
 
3
3
  describe Chore::Strategy::SingleWorkerStrategy do
4
4
  let(:manager) { double('Manager') }
5
+ let(:job_timeout) { 60 }
6
+ let(:job) { Chore::UnitOfWork.new(SecureRandom.uuid, nil, 'test', job_timeout, Chore::Encoder::JsonEncoder.encode(TestJob.job_hash([1,2,"3"])), 0) }
5
7
  subject { described_class.new(manager) }
6
8
 
7
9
  describe '#stop!' do
@@ -31,4 +33,27 @@ describe Chore::Strategy::SingleWorkerStrategy do
31
33
  end
32
34
  end
33
35
 
36
+ describe '#assign' do
37
+ let(:worker) { double('Worker', start: nil) }
38
+
39
+ it 'starts a new worker' do
40
+ expect(Chore::Worker).to receive(:new).with(job, {}).and_return(worker)
41
+ subject.assign(job)
42
+ end
43
+
44
+ it 'can be called multiple times' do
45
+ expect(Chore::Worker).to receive(:new).twice.with(job, {}).and_return(worker)
46
+ 2.times { subject.assign(job) }
47
+ end
48
+
49
+ it 'should release the worker if an exception occurs' do
50
+ allow_any_instance_of(Chore::Worker).to receive(:start).and_raise(ArgumentError)
51
+ expect(subject).to receive(:release_worker)
52
+
53
+ begin
54
+ subject.assign(job)
55
+ rescue ArgumentError
56
+ end
57
+ end
58
+ end
34
59
  end
@@ -2,6 +2,10 @@ require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
2
2
 
3
3
  describe Chore::Worker do
4
4
 
5
+ before(:each) do
6
+ allow(consumer).to receive(:duplicate_message?).and_return(false)
7
+ end
8
+
5
9
  class SimpleJob
6
10
  include Chore::Job
7
11
  queue_options :name => 'test',
@@ -13,7 +17,31 @@ describe Chore::Worker do
13
17
  end
14
18
  end
15
19
 
16
- let(:consumer) { double('consumer', :complete => nil) }
20
+ class SimpleDedupeJob
21
+ include Chore::Job
22
+ queue_options :name => 'dedupe_test',
23
+ :publisher => FakePublisher,
24
+ :max_attempts => 100,
25
+ :dedupe_lambda => lambda { |first, second, third| first }
26
+
27
+ def perform(first, second, third)
28
+ return second
29
+ end
30
+ end
31
+
32
+ class InvalidDedupeJob
33
+ include Chore::Job
34
+ queue_options :name => 'invalid_dedupe_test',
35
+ :publisher => FakePublisher,
36
+ :max_attempts => 100,
37
+ :dedupe_lambda => lambda { |first, second, third| first }
38
+
39
+ def perform(first, second)
40
+ return second
41
+ end
42
+ end
43
+
44
+ let(:consumer) { double('consumer', :complete => nil, :reject => nil) }
17
45
  let(:job_args) { [1,2,'3'] }
18
46
  let(:job) { SimpleJob.job_hash(job_args) }
19
47
 
@@ -24,9 +52,9 @@ describe Chore::Worker do
24
52
 
25
53
  shared_examples_for "a worker" do
26
54
  it 'processing a single job' do
27
- work = Chore::UnitOfWork.new('1', 'test', 60, encoded_job, 0, consumer)
55
+ work = Chore::UnitOfWork.new('1', nil, 'test', 60, encoded_job, 0, consumer)
28
56
  SimpleJob.should_receive(:perform).with(*payload)
29
- consumer.should_receive(:complete).with('1')
57
+ consumer.should_receive(:complete).with('1', nil)
30
58
  w = Chore::Worker.new(work, {:payload_handler => payload_handler})
31
59
  w.start
32
60
  end
@@ -34,12 +62,39 @@ describe Chore::Worker do
34
62
  it 'processing multiple jobs' do
35
63
  work = []
36
64
  10.times do |i|
37
- work << Chore::UnitOfWork.new(i, 'test', 60, encoded_job, 0, consumer)
65
+ work << Chore::UnitOfWork.new(i, nil, 'test', 60, encoded_job, 0, consumer)
38
66
  end
39
67
  SimpleJob.should_receive(:perform).exactly(10).times
40
68
  consumer.should_receive(:complete).exactly(10).times
41
69
  Chore::Worker.start(work, {:payload_handler => payload_handler})
42
70
  end
71
+
72
+ context 'when the job has a dedupe_lambda defined' do
73
+ context 'when the value being deduped on is unique' do
74
+ let(:job_args) { [rand,2,'3'] }
75
+ let(:encoded_job) { Chore::Encoder::JsonEncoder.encode(job) }
76
+ let(:job) { SimpleDedupeJob.job_hash(job_args) }
77
+ it 'should call complete for each unique value' do
78
+ allow(consumer).to receive(:duplicate_message?).and_return(false)
79
+ work = []
80
+ work << Chore::UnitOfWork.new(1, nil, 'dedupe_test', 60, Chore::Encoder::JsonEncoder.encode(SimpleDedupeJob.job_hash([rand,2,'3'])), 0, consumer)
81
+ SimpleDedupeJob.should_receive(:perform).exactly(1).times
82
+ consumer.should_receive(:complete).exactly(1).times
83
+ Chore::Worker.start(work, {:payload_handler => payload_handler})
84
+ end
85
+ end
86
+
87
+ context 'when the dedupe lambda does not take the same number of arguments as perform' do
88
+ it 'should raise an error and not complete the job' do
89
+ work = []
90
+ work << Chore::UnitOfWork.new(1, nil, 'invalid_dedupe_test', 60, Chore::Encoder::JsonEncoder.encode(InvalidDedupeJob.job_hash([rand,2,'3'])), 0, consumer)
91
+ work << Chore::UnitOfWork.new(2, nil, 'invalid_dedupe_test', 60, Chore::Encoder::JsonEncoder.encode(InvalidDedupeJob.job_hash([rand,2,'3'])), 0, consumer)
92
+ work << Chore::UnitOfWork.new(1, nil, 'invalid_dedupe_test', 60, Chore::Encoder::JsonEncoder.encode(InvalidDedupeJob.job_hash([rand,2,'3'])), 0, consumer)
93
+ consumer.should_not_receive(:complete)
94
+ Chore::Worker.start(work, {:payload_handler => payload_handler})
95
+ end
96
+ end
97
+ end
43
98
  end
44
99
 
45
100
  describe "with default payload handler" do
@@ -54,7 +109,7 @@ describe Chore::Worker do
54
109
  let(:queue_timeouts) { [10, 20, 30] }
55
110
  let(:work) do
56
111
  queue_timeouts.map do |queue_timeout|
57
- Chore::UnitOfWork.new('1', 'test', queue_timeout, Chore::Encoder::JsonEncoder.encode(job), 0, consumer)
112
+ Chore::UnitOfWork.new('1', nil, 'test', queue_timeout, Chore::Encoder::JsonEncoder.encode(job), 0, consumer)
58
113
  end
59
114
  end
60
115
  let(:worker) do
@@ -85,26 +140,32 @@ describe Chore::Worker do
85
140
  let(:job) { "Not-A-Valid-Json-String" }
86
141
 
87
142
  it 'should fail cleanly' do
88
- work = Chore::UnitOfWork.new(2,'test',60,job,0,consumer)
143
+ work = Chore::UnitOfWork.new(2,nil,'test',60,job,0,consumer)
89
144
  consumer.should_not_receive(:complete)
90
145
  Chore.should_receive(:run_hooks_for).with(:on_failure, job, anything())
91
146
  Chore::Worker.start(work)
92
147
  end
93
148
 
149
+ it 'should reject job' do
150
+ work = Chore::UnitOfWork.new(2,nil,'test',60,job,0,consumer)
151
+ consumer.should_receive(:reject).with(2)
152
+ Chore::Worker.start(work)
153
+ end
154
+
94
155
  context 'more than the maximum allowed times' do
95
156
  before(:each) do
96
157
  Chore.config.stub(:max_attempts).and_return(10)
97
158
  end
98
159
 
99
160
  it 'should permanently fail' do
100
- work = Chore::UnitOfWork.new(2,'test',60,job,9,consumer)
161
+ work = Chore::UnitOfWork.new(2,nil,'test',60,job,9,consumer)
101
162
  Chore.should_receive(:run_hooks_for).with(:on_permanent_failure, 'test', job, anything())
102
163
  Chore::Worker.start(work)
103
164
  end
104
165
 
105
166
  it 'should mark the item as completed' do
106
- work = Chore::UnitOfWork.new(2,'test',60,job,9,consumer)
107
- consumer.should_receive(:complete).with(2)
167
+ work = Chore::UnitOfWork.new(2,nil,'test',60,job,9,consumer)
168
+ consumer.should_receive(:complete).with(2, nil)
108
169
  Chore::Worker.start(work)
109
170
  end
110
171
  end
@@ -120,23 +181,30 @@ describe Chore::Worker do
120
181
  end
121
182
 
122
183
  it 'should fail cleanly' do
123
- work = Chore::UnitOfWork.new(2,'test',60,encoded_job,0,consumer)
184
+ work = Chore::UnitOfWork.new(2,nil,'test',60,encoded_job,0,consumer)
124
185
  consumer.should_not_receive(:complete)
125
186
  SimpleJob.should_receive(:run_hooks_for).with(:on_failure, parsed_job, anything())
126
187
 
127
188
  Chore::Worker.start(work)
128
189
  end
129
190
 
191
+ it 'should reject job' do
192
+ work = Chore::UnitOfWork.new(2,nil,'test',60,encoded_job,0,consumer)
193
+ consumer.should_receive(:reject).with(2)
194
+
195
+ Chore::Worker.start(work)
196
+ end
197
+
130
198
  context 'more than the maximum allowed times' do
131
199
  it 'should permanently fail' do
132
- work = Chore::UnitOfWork.new(2,'test',60,encoded_job,999,consumer)
200
+ work = Chore::UnitOfWork.new(2,nil,'test',60,encoded_job,999,consumer)
133
201
  SimpleJob.should_receive(:run_hooks_for).with(:on_permanent_failure, 'test', parsed_job, anything())
134
202
  Chore::Worker.start(work)
135
203
  end
136
204
 
137
205
  it 'should mark the item as completed' do
138
- work = Chore::UnitOfWork.new(2,'test',60,encoded_job,999,consumer)
139
- consumer.should_receive(:complete).with(2)
206
+ work = Chore::UnitOfWork.new(2,nil,'test',60,encoded_job,999,consumer)
207
+ consumer.should_receive(:complete).with(2, nil)
140
208
  Chore::Worker.start(work)
141
209
  end
142
210
  end
@@ -146,7 +214,7 @@ describe Chore::Worker do
146
214
  describe 'delaying retries' do
147
215
  let(:encoded_job) { Chore::Encoder::JsonEncoder.encode(job) }
148
216
  let(:parsed_job) { JSON.parse(encoded_job) }
149
- let(:work) { Chore::UnitOfWork.new(2, 'test', 60, encoded_job, 0, consumer) }
217
+ let(:work) { Chore::UnitOfWork.new(2, nil, 'test', 60, encoded_job, 0, consumer) }
150
218
 
151
219
  before(:each) do
152
220
  SimpleJob.options[:backoff] = lambda { |work| work.current_attempt }
@@ -26,7 +26,7 @@ class FakePublisher < Chore::Publisher
26
26
  end
27
27
  end
28
28
 
29
- TestMessage = Struct.new(:handle, :queue, :body, :receive_count) do
29
+ TestMessage = Struct.new(:handle, :receipt_handle, :queue, :body, :receive_count) do
30
30
  def empty?
31
31
  false
32
32
  end
@@ -0,0 +1,18 @@
1
+ describe Chore::Queues::SQS do
2
+ RSpec.shared_context 'fake objects' do
3
+ let(:queue_name) { 'test_queue' }
4
+ let(:queue_url) { "http://amazon.sqs.url/queues/#{queue_name}" }
5
+
6
+ let(:queue) do
7
+ double(Aws::SQS::Queue,
8
+ attributes: {'VisibilityTimeout' => rand(10)}
9
+ )
10
+ end
11
+
12
+ let(:sqs) do
13
+ double(Aws::SQS::Client,
14
+ get_queue_url: double(Aws::SQS::Types::GetQueueUrlResult, :queue_url => queue_url),
15
+ )
16
+ end
17
+ end
18
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chore-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.8.2
4
+ version: 4.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tapjoy
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-02-02 00:00:00.000000000 Z
11
+ date: 2020-09-14 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -25,25 +25,19 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
27
  - !ruby/object:Gem::Dependency
28
- name: aws-sdk-v1
28
+ name: aws-sdk-sqs
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
31
  - - "~>"
32
32
  - !ruby/object:Gem::Version
33
- version: '1.56'
34
- - - ">="
35
- - !ruby/object:Gem::Version
36
- version: 1.56.0
33
+ version: '1'
37
34
  type: :runtime
38
35
  prerelease: false
39
36
  version_requirements: !ruby/object:Gem::Requirement
40
37
  requirements:
41
38
  - - "~>"
42
39
  - !ruby/object:Gem::Version
43
- version: '1.56'
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: 1.56.0
40
+ version: '1'
47
41
  - !ruby/object:Gem::Dependency
48
42
  name: thread
49
43
  requirement: !ruby/object:Gem::Requirement
@@ -58,20 +52,34 @@ dependencies:
58
52
  - - "~>"
59
53
  - !ruby/object:Gem::Version
60
54
  version: 0.1.3
55
+ - !ruby/object:Gem::Dependency
56
+ name: get_process_mem
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.2.0
62
+ type: :runtime
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.2.0
61
69
  - !ruby/object:Gem::Dependency
62
70
  name: rspec
63
71
  requirement: !ruby/object:Gem::Requirement
64
72
  requirements:
65
73
  - - "~>"
66
74
  - !ruby/object:Gem::Version
67
- version: 3.3.0
75
+ version: '3.3'
68
76
  type: :development
69
77
  prerelease: false
70
78
  version_requirements: !ruby/object:Gem::Requirement
71
79
  requirements:
72
80
  - - "~>"
73
81
  - !ruby/object:Gem::Version
74
- version: 3.3.0
82
+ version: '3.3'
75
83
  - !ruby/object:Gem::Dependency
76
84
  name: rdoc
77
85
  requirement: !ruby/object:Gem::Requirement
@@ -137,7 +145,15 @@ files:
137
145
  - lib/chore/strategies/consumer/batcher.rb
138
146
  - lib/chore/strategies/consumer/single_consumer_strategy.rb
139
147
  - lib/chore/strategies/consumer/threaded_consumer_strategy.rb
148
+ - lib/chore/strategies/consumer/throttled_consumer_strategy.rb
140
149
  - lib/chore/strategies/worker/forked_worker_strategy.rb
150
+ - lib/chore/strategies/worker/helpers/ipc.rb
151
+ - lib/chore/strategies/worker/helpers/preforked_worker.rb
152
+ - lib/chore/strategies/worker/helpers/work_distributor.rb
153
+ - lib/chore/strategies/worker/helpers/worker_info.rb
154
+ - lib/chore/strategies/worker/helpers/worker_killer.rb
155
+ - lib/chore/strategies/worker/helpers/worker_manager.rb
156
+ - lib/chore/strategies/worker/preforked_worker_strategy.rb
141
157
  - lib/chore/strategies/worker/single_worker_strategy.rb
142
158
  - lib/chore/tasks/queues.task
143
159
  - lib/chore/unit_of_work.rb
@@ -160,11 +176,20 @@ files:
160
176
  - spec/chore/strategies/consumer/batcher_spec.rb
161
177
  - spec/chore/strategies/consumer/single_consumer_strategy_spec.rb
162
178
  - spec/chore/strategies/consumer/threaded_consumer_strategy_spec.rb
179
+ - spec/chore/strategies/consumer/throttled_consumer_strategy_spec.rb
163
180
  - spec/chore/strategies/worker/forked_worker_strategy_spec.rb
181
+ - spec/chore/strategies/worker/helpers/ipc_spec.rb
182
+ - spec/chore/strategies/worker/helpers/preforked_worker_spec.rb
183
+ - spec/chore/strategies/worker/helpers/work_distributor_spec.rb
184
+ - spec/chore/strategies/worker/helpers/worker_info_spec.rb
185
+ - spec/chore/strategies/worker/helpers/worker_killer_spec.rb
186
+ - spec/chore/strategies/worker/helpers/worker_manager_spec.rb
187
+ - spec/chore/strategies/worker/preforked_worker_strategy_spec.rb
164
188
  - spec/chore/strategies/worker/single_worker_strategy_spec.rb
165
189
  - spec/chore/worker_spec.rb
166
190
  - spec/chore_spec.rb
167
191
  - spec/spec_helper.rb
192
+ - spec/support/queues/sqs/fake_objects.rb
168
193
  - spec/test_job.rb
169
194
  homepage: http://github.com/Tapjoy/chore
170
195
  licenses:
@@ -186,9 +211,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
211
  version: '0'
187
212
  requirements: []
188
213
  rubyforge_project:
189
- rubygems_version: 2.4.5
214
+ rubygems_version: 2.5.1
190
215
  signing_key:
191
216
  specification_version: 4
192
217
  summary: Job processing... for the future!
193
218
  test_files: []
194
- has_rdoc: