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.
Files changed (60) hide show
  1. checksums.yaml +5 -13
  2. data/LICENSE.txt +1 -1
  3. data/README.md +172 -153
  4. data/chore-core.gemspec +3 -3
  5. data/lib/chore.rb +29 -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 +17 -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 +10 -16
  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 +6 -6
  21. data/lib/chore/strategies/consumer/single_consumer_strategy.rb +5 -5
  22. data/lib/chore/strategies/consumer/threaded_consumer_strategy.rb +7 -6
  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/unit_of_work.rb +2 -1
  33. data/lib/chore/util.rb +5 -1
  34. data/lib/chore/version.rb +2 -2
  35. data/lib/chore/worker.rb +30 -3
  36. data/spec/chore/cli_spec.rb +2 -2
  37. data/spec/chore/consumer_spec.rb +1 -5
  38. data/spec/chore/duplicate_detector_spec.rb +17 -5
  39. data/spec/chore/fetcher_spec.rb +0 -11
  40. data/spec/chore/manager_spec.rb +7 -0
  41. data/spec/chore/queues/filesystem/filesystem_consumer_spec.rb +74 -16
  42. data/spec/chore/queues/sqs/consumer_spec.rb +117 -78
  43. data/spec/chore/queues/sqs/publisher_spec.rb +49 -60
  44. data/spec/chore/queues/sqs_spec.rb +32 -41
  45. data/spec/chore/strategies/consumer/single_consumer_strategy_spec.rb +3 -3
  46. data/spec/chore/strategies/consumer/threaded_consumer_strategy_spec.rb +6 -6
  47. data/spec/chore/strategies/consumer/throttled_consumer_strategy_spec.rb +165 -0
  48. data/spec/chore/strategies/worker/forked_worker_strategy_spec.rb +6 -1
  49. data/spec/chore/strategies/worker/helpers/ipc_spec.rb +127 -0
  50. data/spec/chore/strategies/worker/helpers/preforked_worker_spec.rb +236 -0
  51. data/spec/chore/strategies/worker/helpers/work_distributor_spec.rb +131 -0
  52. data/spec/chore/strategies/worker/helpers/worker_info_spec.rb +14 -0
  53. data/spec/chore/strategies/worker/helpers/worker_killer_spec.rb +97 -0
  54. data/spec/chore/strategies/worker/helpers/worker_manager_spec.rb +304 -0
  55. data/spec/chore/strategies/worker/preforked_worker_strategy_spec.rb +183 -0
  56. data/spec/chore/strategies/worker/single_worker_strategy_spec.rb +1 -1
  57. data/spec/chore/worker_spec.rb +70 -15
  58. data/spec/spec_helper.rb +1 -1
  59. data/spec/support/queues/sqs/fake_objects.rb +18 -0
  60. metadata +53 -29
@@ -3,7 +3,7 @@ require 'spec_helper'
3
3
  describe Chore::Strategy::SingleWorkerStrategy do
4
4
  let(:manager) { double('Manager') }
5
5
  let(:job_timeout) { 60 }
6
- let(:job) { Chore::UnitOfWork.new(SecureRandom.uuid, 'test', job_timeout, Chore::Encoder::JsonEncoder.encode(TestJob.job_hash([1,2,"3"])), 0) }
6
+ let(:job) { Chore::UnitOfWork.new(SecureRandom.uuid, nil, 'test', job_timeout, Chore::Encoder::JsonEncoder.encode(TestJob.job_hash([1,2,"3"])), 0) }
7
7
  subject { described_class.new(manager) }
8
8
 
9
9
  describe '#stop!' do
@@ -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,6 +17,30 @@ describe Chore::Worker do
13
17
  end
14
18
  end
15
19
 
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
+
16
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) }
@@ -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,14 +140,14 @@ 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
 
94
149
  it 'should reject job' do
95
- work = Chore::UnitOfWork.new(2,'test',60,job,0,consumer)
150
+ work = Chore::UnitOfWork.new(2,nil,'test',60,job,0,consumer)
96
151
  consumer.should_receive(:reject).with(2)
97
152
  Chore::Worker.start(work)
98
153
  end
@@ -103,14 +158,14 @@ describe Chore::Worker do
103
158
  end
104
159
 
105
160
  it 'should permanently fail' do
106
- work = Chore::UnitOfWork.new(2,'test',60,job,9,consumer)
161
+ work = Chore::UnitOfWork.new(2,nil,'test',60,job,9,consumer)
107
162
  Chore.should_receive(:run_hooks_for).with(:on_permanent_failure, 'test', job, anything())
108
163
  Chore::Worker.start(work)
109
164
  end
110
165
 
111
166
  it 'should mark the item as completed' do
112
- work = Chore::UnitOfWork.new(2,'test',60,job,9,consumer)
113
- 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)
114
169
  Chore::Worker.start(work)
115
170
  end
116
171
  end
@@ -126,7 +181,7 @@ describe Chore::Worker do
126
181
  end
127
182
 
128
183
  it 'should fail cleanly' do
129
- work = Chore::UnitOfWork.new(2,'test',60,encoded_job,0,consumer)
184
+ work = Chore::UnitOfWork.new(2,nil,'test',60,encoded_job,0,consumer)
130
185
  consumer.should_not_receive(:complete)
131
186
  SimpleJob.should_receive(:run_hooks_for).with(:on_failure, parsed_job, anything())
132
187
 
@@ -134,7 +189,7 @@ describe Chore::Worker do
134
189
  end
135
190
 
136
191
  it 'should reject job' do
137
- work = Chore::UnitOfWork.new(2,'test',60,encoded_job,0,consumer)
192
+ work = Chore::UnitOfWork.new(2,nil,'test',60,encoded_job,0,consumer)
138
193
  consumer.should_receive(:reject).with(2)
139
194
 
140
195
  Chore::Worker.start(work)
@@ -142,14 +197,14 @@ describe Chore::Worker do
142
197
 
143
198
  context 'more than the maximum allowed times' do
144
199
  it 'should permanently fail' do
145
- work = Chore::UnitOfWork.new(2,'test',60,encoded_job,999,consumer)
200
+ work = Chore::UnitOfWork.new(2,nil,'test',60,encoded_job,999,consumer)
146
201
  SimpleJob.should_receive(:run_hooks_for).with(:on_permanent_failure, 'test', parsed_job, anything())
147
202
  Chore::Worker.start(work)
148
203
  end
149
204
 
150
205
  it 'should mark the item as completed' do
151
- work = Chore::UnitOfWork.new(2,'test',60,encoded_job,999,consumer)
152
- 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)
153
208
  Chore::Worker.start(work)
154
209
  end
155
210
  end
@@ -159,7 +214,7 @@ describe Chore::Worker do
159
214
  describe 'delaying retries' do
160
215
  let(:encoded_job) { Chore::Encoder::JsonEncoder.encode(job) }
161
216
  let(:parsed_job) { JSON.parse(encoded_job) }
162
- 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) }
163
218
 
164
219
  before(:each) do
165
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,103 +1,111 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chore-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.10.0
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-03-24 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
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
- - - ! '>='
17
+ - - ">="
18
18
  - !ruby/object:Gem::Version
19
19
  version: '0'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
- - - ! '>='
24
+ - - ">="
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
- - - ~>
42
- - !ruby/object:Gem::Version
43
- version: '1.56'
44
- - - ! '>='
38
+ - - "~>"
45
39
  - !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
50
44
  requirements:
51
- - - ~>
45
+ - - "~>"
52
46
  - !ruby/object:Gem::Version
53
47
  version: 0.1.3
54
48
  type: :runtime
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
51
  requirements:
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
78
86
  requirements:
79
- - - ~>
87
+ - - "~>"
80
88
  - !ruby/object:Gem::Version
81
89
  version: '3.12'
82
90
  type: :development
83
91
  prerelease: false
84
92
  version_requirements: !ruby/object:Gem::Requirement
85
93
  requirements:
86
- - - ~>
94
+ - - "~>"
87
95
  - !ruby/object:Gem::Version
88
96
  version: '3.12'
89
97
  - !ruby/object:Gem::Dependency
90
98
  name: bundler
91
99
  requirement: !ruby/object:Gem::Requirement
92
100
  requirements:
93
- - - ! '>='
101
+ - - ">="
94
102
  - !ruby/object:Gem::Version
95
103
  version: '0'
96
104
  type: :development
97
105
  prerelease: false
98
106
  version_requirements: !ruby/object:Gem::Requirement
99
107
  requirements:
100
- - - ! '>='
108
+ - - ">="
101
109
  - !ruby/object:Gem::Version
102
110
  version: '0'
103
111
  description: Job processing with pluggable backends and strategies
@@ -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:
@@ -176,19 +201,18 @@ require_paths:
176
201
  - lib
177
202
  required_ruby_version: !ruby/object:Gem::Requirement
178
203
  requirements:
179
- - - ! '>='
204
+ - - ">="
180
205
  - !ruby/object:Gem::Version
181
206
  version: '0'
182
207
  required_rubygems_version: !ruby/object:Gem::Requirement
183
208
  requirements:
184
- - - ! '>='
209
+ - - ">="
185
210
  - !ruby/object:Gem::Version
186
211
  version: '0'
187
212
  requirements: []
188
213
  rubyforge_project:
189
- rubygems_version: 2.4.8
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: