chore-core 1.9.0 → 1.10.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 CHANGED
@@ -1,7 +1,15 @@
1
1
  ---
2
- SHA1:
3
- metadata.gz: 0800ed952e9c16ccde3058ff9db8a4b9a72adf44
4
- data.tar.gz: b24b312e93158e7942ae11896d9680f9f8a7714d
2
+ !binary "U0hBMQ==":
3
+ metadata.gz: !binary |-
4
+ OWVhNTgxZTYxMzNkNDVjODU1NTI5YmJjOGYxOWU4NmUzNDkzMDljYw==
5
+ data.tar.gz: !binary |-
6
+ ZTliZWFkNzRhZDZlZDBiZWZlNjg4MDcxNDEzMTlhNDkwNmJkOWU4NA==
5
7
  SHA512:
6
- metadata.gz: 86f131b78103e360f0219b7b55a53da68338e676791dedcea638130e38e132665a4d33cf2bd0f90e78957184dd8b9d19ea88b7801866097b276d113debb654bd
7
- data.tar.gz: 5f32aa7d1db7aab0579b1bfb43c31497502f76964e71e4d9faf0d6c1230be157901694602cb8a76f82e6c7627d2a74337e82f377a71652f03cbd18f1dfd4b23f
8
+ metadata.gz: !binary |-
9
+ MDJkYmVlYWY4YTljMTA4ZjkxNGFlNGYxMDRiYThhNTJiYTJjNjhkYzVkNWFl
10
+ YTUzNjBlMDIxYjM1MTcxNjE4NzU1YjdkNGVmOWY1Y2IzODg1MTQ5YjIxZGUx
11
+ ZWI5N2U4ZGQwZGRhYTVkZTRiZmMxYzY0NGM1MjQ1YzM5NmJiZTM=
12
+ data.tar.gz: !binary |-
13
+ Mjc2ODk3ZmFjZjc2ZDdiODlkMTA4ODQzM2I1N2JiZDI5M2QwZjU2ODNkOWRl
14
+ NGY4ZDg3NDRiMDAzMTUxNzM0MGQxNTNiNDM4ZmMwMmVhOTQzZTgwOTc4ZTc2
15
+ MTg1YjI4Y2M1ZjE2YTM5ZDJiNTMwY2NkMjNjNTlmMTAyZmM1YTQ=
data/README.md CHANGED
@@ -33,6 +33,7 @@ Other options include:
33
33
  --threads-per-queue 4 # number of threads per queue for consuming from a given queue.
34
34
  --dedupe-servers # if using SQS or similiar queue with at-least once delivery and your memcache is running on something other than localhost
35
35
  --batch-size 50 # how many messages are batched together before handing them to a worker
36
+ --batch-timeout 20 # maximum number of seconds to wait until handing a message over to a worker
36
37
  --queue_prefix prefixy # A prefix to prepend to queue names, mainly for development and qa testing purposes
37
38
  --max-attempts 100 # The maximum number of times a job can be attempted
38
39
  --dupe-on-cache-failure # Determines the deduping behavior when a cache connection error occurs. When set to `false`, the message is assumed not to be a duplicate. Defaults to `false`.
@@ -92,6 +93,7 @@ Chore.configure do |c|
92
93
  c.max_attempts = 100
93
94
  ...
94
95
  c.batch_size = 50
96
+ c.batch_timeout = 20
95
97
  end
96
98
  ```
97
99
 
@@ -34,6 +34,7 @@ module Chore #:nodoc:
34
34
  :fetcher => Fetcher,
35
35
  :consumer_strategy => Strategy::ThreadedConsumerStrategy,
36
36
  :batch_size => 50,
37
+ :batch_timeout => 20,
37
38
  :log_level => Logger::WARN,
38
39
  :log_path => STDOUT,
39
40
  :default_queue_timeout => (12 * 60 * 60), # 12 hours
@@ -186,6 +187,7 @@ module Chore #:nodoc:
186
187
  # Chore.configure do |c|
187
188
  # c.consumer = Chore::Queues::SQS::Consumer
188
189
  # c.batch_size = 50
190
+ # c.batch_timeout = 20
189
191
  # end
190
192
  def self.configure(opts={})
191
193
  @config = (@config ? @config.merge_hash(opts) : Chore::Configuration.new(DEFAULT_OPTIONS.merge(opts)))
@@ -11,27 +11,27 @@ module Chore
11
11
  @size = size
12
12
  @batch = []
13
13
  @mutex = Mutex.new
14
- @last_message = nil
15
14
  @callback = nil
16
15
  @running = true
17
16
  end
18
17
 
19
18
  # The main entry point of the Batcher, <tt>schedule</tt> begins a thread with the provided +batch_timeout+
20
19
  # as the only argument. While the Batcher is running, it will attempt to check if either the batch is full,
21
- # or if the +batch_timeout+ has elapsed since the last batch was executed. If the batch is full, it will be executed.
22
- # If the +batch_timeout+ has elapsed, as soon as the next message enters the batch, it will be executed.
20
+ # or if the +batch_timeout+ has elapsed since the oldest message was added. If either case is true, the
21
+ # items in the batch will be executed.
23
22
  #
24
23
  # Calling <tt>stop</tt> will cause the thread to finish it's current check, and exit
25
- def schedule(batch_timeout=20)
24
+ def schedule(batch_timeout)
26
25
  @thread = Thread.new(batch_timeout) do |timeout|
27
26
  Chore.logger.info "Batching timeout thread starting"
28
27
  while @running do
29
28
  begin
30
- Chore.logger.debug "Last message added to batch: #{@last_message}: #{@batch.size}"
31
- if @last_message && Time.now > (@last_message + timeout)
32
- Chore.logger.debug "Batching timeout reached (#{@last_message + timeout}), current size: #{@batch.size}"
29
+ oldest_item = @batch.first
30
+ timestamp = oldest_item && oldest_item.created_at
31
+ Chore.logger.debug "Oldest message in batch: #{timestamp}, size: #{@batch.size}"
32
+ if timestamp && Time.now > (timestamp + timeout)
33
+ Chore.logger.debug "Batching timeout reached (#{timestamp + timeout}), current size: #{@batch.size}"
33
34
  self.execute(true)
34
- @last_message = nil
35
35
  end
36
36
  sleep(1)
37
37
  rescue => e
@@ -44,7 +44,6 @@ module Chore
44
44
  # Adds the +item+ to the current batch
45
45
  def add(item)
46
46
  @batch << item
47
- @last_message = Time.now
48
47
  execute if ready?
49
48
  end
50
49
 
@@ -5,13 +5,14 @@ module Chore
5
5
  attr_accessor :batcher
6
6
 
7
7
  Chore::CLI.register_option 'batch_size', '--batch-size SIZE', Integer, 'Number of items to collect for a single worker to process'
8
+ Chore::CLI.register_option 'batch_timeout', '--batch-timeout SIZE', Integer, 'Maximum number of seconds to wait until processing a message'
8
9
  Chore::CLI.register_option 'threads_per_queue', '--threads-per-queue NUM_THREADS', Integer, 'Number of threads to create for each named queue'
9
10
 
10
11
  def initialize(fetcher)
11
12
  @fetcher = fetcher
12
13
  @batcher = Batcher.new(Chore.config.batch_size)
13
14
  @batcher.callback = lambda { |batch| @fetcher.manager.assign(batch) }
14
- @batcher.schedule
15
+ @batcher.schedule(Chore.config.batch_timeout)
15
16
  @running = true
16
17
  end
17
18
 
@@ -9,6 +9,14 @@ module Chore
9
9
  # * +:consumer+ The consumer instance used to fetch this message. Most queue implementations won't need access to this, but some (RabbitMQ) will. So we
10
10
  # make sure to pass it along with each message. This instance will be used by the Worker for things like <tt>complete</tt> and </tt>reject</tt>.
11
11
  class UnitOfWork < Struct.new(:id,:queue_name,:queue_timeout,:message,:previous_attempts,:consumer,:decoded_message, :klass)
12
+ # The time at which this unit of work was created
13
+ attr_accessor :created_at
14
+
15
+ def initialize(*) #:nodoc:
16
+ super
17
+ @created_at = Time.now
18
+ end
19
+
12
20
  # The current attempt number for the worker processing this message.
13
21
  def current_attempt
14
22
  previous_attempts + 1
@@ -1,7 +1,7 @@
1
1
  module Chore
2
2
  module Version #:nodoc:
3
3
  MAJOR = 1
4
- MINOR = 9
4
+ MINOR = 10
5
5
  PATCH = 0
6
6
 
7
7
  STRING = [ MAJOR, MINOR, PATCH ].join('.')
@@ -90,4 +90,54 @@ describe Chore::Strategy::Batcher do
90
90
  subject.batch.should == ['test']
91
91
  end
92
92
  end
93
+
94
+ describe 'schedule' do
95
+ let(:timeout) { 5 }
96
+ let(:batch) { [] }
97
+
98
+ before(:each) do
99
+ Thread.stub(:new) do |&block|
100
+ # Stop the batcher on the next iteration
101
+ subject.stub(:sleep) { subject.stop }
102
+
103
+ # Run the scheduling thread
104
+ block.call(timeout)
105
+ end
106
+
107
+ subject.batch = batch.dup
108
+ end
109
+
110
+ context 'with no items' do
111
+ it 'should not invoke the callback' do
112
+ callback.should_not_receive(:call)
113
+ subject.schedule(timeout)
114
+ end
115
+ end
116
+
117
+ context 'with new items' do
118
+ let(:batch) do
119
+ [
120
+ Chore::UnitOfWork.new.tap {|work| work.created_at = Time.now - 2}
121
+ ]
122
+ end
123
+
124
+ it 'should not invoke the callback' do
125
+ callback.should_not_receive(:call).with(batch)
126
+ subject.schedule(timeout)
127
+ end
128
+ end
129
+
130
+ context 'with old items' do
131
+ let(:batch) do
132
+ [
133
+ Chore::UnitOfWork.new.tap {|work| work.created_at = Time.now - 6}
134
+ ]
135
+ end
136
+
137
+ it 'should invoke the callback' do
138
+ callback.should_receive(:call).with(batch)
139
+ subject.schedule(timeout)
140
+ end
141
+ end
142
+ end
93
143
  end
@@ -51,6 +51,7 @@ describe Chore::Strategy::ThreadedConsumerStrategy do
51
51
  work.message.should == "test"
52
52
  work.previous_attempts.should == 0
53
53
  work.current_attempt.should == 1
54
+ work.created_at.should_not be_nil
54
55
  end
55
56
  end
56
57
 
metadata CHANGED
@@ -1,103 +1,103 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: chore-core
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.9.0
4
+ version: 1.10.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-09 00:00:00.000000000 Z
11
+ date: 2016-03-24 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
28
  name: aws-sdk-v1
29
29
  requirement: !ruby/object:Gem::Requirement
30
30
  requirements:
31
- - - "~>"
31
+ - - ~>
32
32
  - !ruby/object:Gem::Version
33
33
  version: '1.56'
34
- - - ">="
34
+ - - ! '>='
35
35
  - !ruby/object:Gem::Version
36
36
  version: 1.56.0
37
37
  type: :runtime
38
38
  prerelease: false
39
39
  version_requirements: !ruby/object:Gem::Requirement
40
40
  requirements:
41
- - - "~>"
41
+ - - ~>
42
42
  - !ruby/object:Gem::Version
43
43
  version: '1.56'
44
- - - ">="
44
+ - - ! '>='
45
45
  - !ruby/object:Gem::Version
46
46
  version: 1.56.0
47
47
  - !ruby/object:Gem::Dependency
48
48
  name: thread
49
49
  requirement: !ruby/object:Gem::Requirement
50
50
  requirements:
51
- - - "~>"
51
+ - - ~>
52
52
  - !ruby/object:Gem::Version
53
53
  version: 0.1.3
54
54
  type: :runtime
55
55
  prerelease: false
56
56
  version_requirements: !ruby/object:Gem::Requirement
57
57
  requirements:
58
- - - "~>"
58
+ - - ~>
59
59
  - !ruby/object:Gem::Version
60
60
  version: 0.1.3
61
61
  - !ruby/object:Gem::Dependency
62
62
  name: rspec
63
63
  requirement: !ruby/object:Gem::Requirement
64
64
  requirements:
65
- - - "~>"
65
+ - - ~>
66
66
  - !ruby/object:Gem::Version
67
67
  version: 3.3.0
68
68
  type: :development
69
69
  prerelease: false
70
70
  version_requirements: !ruby/object:Gem::Requirement
71
71
  requirements:
72
- - - "~>"
72
+ - - ~>
73
73
  - !ruby/object:Gem::Version
74
74
  version: 3.3.0
75
75
  - !ruby/object:Gem::Dependency
76
76
  name: rdoc
77
77
  requirement: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - "~>"
79
+ - - ~>
80
80
  - !ruby/object:Gem::Version
81
81
  version: '3.12'
82
82
  type: :development
83
83
  prerelease: false
84
84
  version_requirements: !ruby/object:Gem::Requirement
85
85
  requirements:
86
- - - "~>"
86
+ - - ~>
87
87
  - !ruby/object:Gem::Version
88
88
  version: '3.12'
89
89
  - !ruby/object:Gem::Dependency
90
90
  name: bundler
91
91
  requirement: !ruby/object:Gem::Requirement
92
92
  requirements:
93
- - - ">="
93
+ - - ! '>='
94
94
  - !ruby/object:Gem::Version
95
95
  version: '0'
96
96
  type: :development
97
97
  prerelease: false
98
98
  version_requirements: !ruby/object:Gem::Requirement
99
99
  requirements:
100
- - - ">="
100
+ - - ! '>='
101
101
  - !ruby/object:Gem::Version
102
102
  version: '0'
103
103
  description: Job processing with pluggable backends and strategies
@@ -176,12 +176,12 @@ require_paths:
176
176
  - lib
177
177
  required_ruby_version: !ruby/object:Gem::Requirement
178
178
  requirements:
179
- - - ">="
179
+ - - ! '>='
180
180
  - !ruby/object:Gem::Version
181
181
  version: '0'
182
182
  required_rubygems_version: !ruby/object:Gem::Requirement
183
183
  requirements:
184
- - - ">="
184
+ - - ! '>='
185
185
  - !ruby/object:Gem::Version
186
186
  version: '0'
187
187
  requirements: []
@@ -191,3 +191,4 @@ signing_key:
191
191
  specification_version: 4
192
192
  summary: Job processing... for the future!
193
193
  test_files: []
194
+ has_rdoc: