sidekiq-grouping 0.0.6 → 1.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ae9e71d0d79bd9af61ed8c49fca7122219849a37
4
- data.tar.gz: c5469b43d3780b36fbe343eca132c86d3d200c34
3
+ metadata.gz: c53ede8cde6f7b04ee9b0ae343f988d564a62944
4
+ data.tar.gz: 22864e990a6ffeaf86ac5ef169072b00d054ef5f
5
5
  SHA512:
6
- metadata.gz: db9e641eb35867c42e2b17eb073b921c42ad992b4846452aff33afb927ea76df2811f7262f89a578c45dbd5d48a0f0e8a0a30be5ea531a8169f1cd9ea7a2ecb8
7
- data.tar.gz: 1fde67a0b91497362100c2608582aaa52e36478a960ec33d9adc99f6552dbe4d2966b713ffa8ef87a3c77391f968894c34c9694801a717d6e68b28e03f148ba7
6
+ metadata.gz: ea56db9c75826ec9fd2cb990ef9cd553049a5200464f3722954a53f0678f353b88ab2477be3ce9c031dc4951460eac4a34618e7dc41c9b6d306887ba2b4460a0
7
+ data.tar.gz: 678f49766262a89976638afae0a47c91e1361b2aeaf80a82a5e0f129019e9f6f76c80b6f8f378774adbc65780eaa8b7f6249132a5a4e733d329c6b1835534757
@@ -2,7 +2,6 @@ language: ruby
2
2
  rvm:
3
3
  - 2.2
4
4
  cache: bundler
5
- sudo: false
6
5
 
7
6
  services:
8
7
  - redis-server
data/README.md CHANGED
@@ -1,14 +1,16 @@
1
1
  # Sidekiq::Grouping
2
2
 
3
- Lets you batch similar tasks to run them all as a single task.
3
+ <a href="https://evilmartians.com/?utm_source=sidekiq-grouping-gem">
4
+ <img src="https://evilmartians.com/badges/sponsored-by-evil-martians.svg" alt="Sponsored by Evil Martians" width="236" height="54">
5
+ </a>
4
6
 
5
- Allows identical sidekiq jobs to be processed with a single background call.
7
+ Allows to combine similar sidekiq jobs into groups to process them at once.
6
8
 
7
9
  Useful for:
8
10
  * Grouping asynchronous API index calls into bulks for bulk updating/indexing.
9
11
  * Periodical batch updating of recently changing database counters.
10
12
 
11
- Sponsored by [Evil Martians](http://evilmartians.com)
13
+ *NOTE:* As of 1.0 `batch_size` renamed to `batch_flush_size`.
12
14
 
13
15
  ## Usage
14
16
 
@@ -19,9 +21,9 @@ class ElasticBulkIndexWorker
19
21
  include Sidekiq::Worker
20
22
 
21
23
  sidekiq_options(
22
- queue: :batched_by_size,
23
- batch_size: 30, # Jobs will be combined to groups of 30 items
24
- batch_flush_interval: 60, # Combined jobs will be executed at least every 60 seconds
24
+ queue: :elasic_bulks,
25
+ batch_flush_size: 30, # Jobs will be combined when queue size exceeds 30
26
+ batch_flush_interval: 60, # Jobs will be combined every 60 seconds
25
27
  retry: 5
26
28
  )
27
29
 
@@ -35,13 +37,15 @@ end
35
37
  Perform a jobs:
36
38
 
37
39
  ```ruby
40
+ # At least 30 times
41
+
38
42
  ElasticBulkIndexWorker.perform_async({ delete: { _index: 'test', _id: 5, _type: 'user' } })
39
43
  ElasticBulkIndexWorker.perform_async({ delete: { _index: 'test', _id: 6, _type: 'user' } })
40
44
  ElasticBulkIndexWorker.perform_async({ delete: { _index: 'test', _id: 7, _type: 'user' } })
41
45
  ...
42
46
  ```
43
47
 
44
- This jobs will be grouped into a single job which will be performed with the single argument containing:
48
+ This jobs will be grouped into the single job with the single argument:
45
49
 
46
50
  ```ruby
47
51
  [
@@ -52,7 +56,58 @@ This jobs will be grouped into a single job which will be performed with the sin
52
56
  ]
53
57
  ```
54
58
 
55
- This will happen for every 30 jobs in a row or every 60 seconds.
59
+ ## Control grouping
60
+
61
+ - If `batch_flush_size` option is set - grouping will be performed when batched queue size exceeds this value or `Sidekiq::Grouping::Config.max_batch_size` (1000 by default).
62
+ - If `batch_flush_interval` option is set - grouping will be performed every given interval.
63
+ - If both are set - grouping will be performed when first condition become true. For example, if `batch_flush_interval` is set to 60 seconds and `batch_flush_size` is set to 5 - group task will be enqueued even if just 3 jobs are in the queue at the end of the minute. In the other hand, if 5 jobs were enqueued during 10 seconds - they will be grouped and enqueued immediately.
64
+
65
+ ## Options
66
+
67
+ - `batch_unique` prevents enqueue of jobs with identical arguments.
68
+
69
+ ```ruby
70
+ class FooWorker
71
+ include Sidekiq::Worker
72
+
73
+ sidekiq_options batch_flush_interval: 10, batch_unique: true
74
+
75
+ def perform(n)
76
+ puts n
77
+ end
78
+ end
79
+
80
+ FooWorker.perform_async(1)
81
+ FooWorker.perform_async(1)
82
+ FooWorker.perform_async(2)
83
+ FooWorker.perform_async(2)
84
+
85
+ # => [[1], [2]]
86
+ ```
87
+
88
+ - `batch_size` is used to control single group size.
89
+
90
+ ```ruby
91
+ class FooWorker
92
+ include Sidekiq::Worker
93
+
94
+ sidekiq_options batch_flush_size: 5, batch_size: 2
95
+
96
+ def perform(n)
97
+ puts n
98
+ end
99
+ end
100
+
101
+ FooWorker.perform_async(1)
102
+ FooWorker.perform_async(2)
103
+ FooWorker.perform_async(3)
104
+ FooWorker.perform_async(4)
105
+ FooWorker.perform_async(5)
106
+
107
+ # => [[1], [2]]
108
+ # => [[3], [4]]
109
+ # => [[5]]
110
+ ```
56
111
 
57
112
  ## Web UI
58
113
 
@@ -69,13 +124,12 @@ require "sidekiq/grouping/web"
69
124
  ```ruby
70
125
  Sidekiq::Grouping::Config.poll_interval = 5 # Amount of time between polling batches
71
126
  Sidekiq::Grouping::Config.max_batch_size = 5000 # Maximum batch size allowed
72
- Sidekiq::Grouping::Config.lock_ttl = 1 # Timeout of lock set when batched job enqueues
127
+ Sidekiq::Grouping::Config.lock_ttl = 1 # Batch queue flush lock timeout job enqueues
73
128
  ```
74
129
 
75
130
  ## TODO
76
131
 
77
132
  1. Add support redis_pool option.
78
- 2. Make able to work together with sidekiq-unique-jobs.
79
133
 
80
134
  ## Installation
81
135
 
@@ -1,18 +1,18 @@
1
1
  require 'active_support/core_ext/string'
2
2
  require 'active_support/configurable'
3
3
  require 'active_support/core_ext/numeric/time'
4
-
5
- require 'sidekiq/grouping/config'
6
- require 'sidekiq/grouping/redis'
7
- require 'sidekiq/grouping/batch'
8
- require 'sidekiq/grouping/middleware'
9
- require 'sidekiq/grouping/logging'
10
- require 'sidekiq/grouping/actor'
11
- require 'sidekiq/grouping/supervisor'
12
4
  require 'sidekiq/grouping/version'
13
5
 
14
6
  module Sidekiq
15
7
  module Grouping
8
+ autoload :Config, 'sidekiq/grouping/config'
9
+ autoload :Redis, 'sidekiq/grouping/redis'
10
+ autoload :Batch, 'sidekiq/grouping/batch'
11
+ autoload :Middleware, 'sidekiq/grouping/middleware'
12
+ autoload :Logging, 'sidekiq/grouping/logging'
13
+ autoload :Actor, 'sidekiq/grouping/actor'
14
+ autoload :Supervisor, 'sidekiq/grouping/supervisor'
15
+
16
16
  class << self
17
17
  attr_writer :logger
18
18
 
@@ -9,6 +9,7 @@ module Sidekiq
9
9
  end
10
10
 
11
11
  private
12
+
12
13
  def start_polling
13
14
  interval = Sidekiq::Grouping::Config.poll_interval
14
15
  info "Start polling of queue batches every #{interval} seconds"
@@ -27,25 +27,32 @@ module Sidekiq
27
27
 
28
28
  def chunk_size
29
29
  worker_class_options['batch_size'] ||
30
- Sidekiq::Grouping::Config.max_batch_size
30
+ Sidekiq::Grouping::Config.max_batch_size
31
+ end
32
+
33
+ def pluck_size
34
+ worker_class_options['batch_flush_size'] ||
35
+ Sidekiq::Grouping::Config.max_batch_size
31
36
  end
32
37
 
33
38
  def pluck
34
39
  if @redis.lock(@name)
35
- @redis.pluck(@name, chunk_size).map { |value| JSON.parse(value) }
40
+ @redis.pluck(@name, pluck_size).map { |value| JSON.parse(value) }
36
41
  end
37
42
  end
38
43
 
39
44
  def flush
40
45
  chunk = pluck
41
- if chunk
42
- set_current_time_as_last
46
+ return unless chunk
47
+
48
+ chunk.each_slice(chunk_size) do |subchunk|
43
49
  Sidekiq::Client.push(
44
50
  'class' => @worker_class,
45
51
  'queue' => @queue,
46
- 'args' => [true, chunk]
52
+ 'args' => [true, subchunk]
47
53
  )
48
54
  end
55
+ set_current_time_as_last
49
56
  end
50
57
 
51
58
  def worker_class_constant
@@ -79,9 +86,11 @@ module Sidekiq
79
86
  end
80
87
 
81
88
  private
89
+
82
90
  def could_flush_on_overflow?
83
- worker_class_options['batch_size'] &&
84
- size >= worker_class_options['batch_size']
91
+ return true if size >= Sidekiq::Grouping::Config.max_batch_size
92
+ worker_class_options['batch_flush_size'] &&
93
+ size >= worker_class_options['batch_flush_size']
85
94
  end
86
95
 
87
96
  def could_flush_on_time?
@@ -94,9 +103,7 @@ module Sidekiq
94
103
  set_current_time_as_last
95
104
  false
96
105
  else
97
- if next_time
98
- next_time < Time.now
99
- end
106
+ next_time < Time.now if next_time
100
107
  end
101
108
  end
102
109
 
@@ -122,7 +129,6 @@ module Sidekiq
122
129
  [klass.classify, queue]
123
130
  end
124
131
  end
125
-
126
132
  end
127
133
  end
128
134
  end
@@ -3,15 +3,15 @@ module Sidekiq
3
3
  module Config
4
4
  include ActiveSupport::Configurable
5
5
 
6
- # Interval batch queue polling
6
+ # Queue size overflow check polling interval
7
7
  config_accessor :poll_interval
8
8
  self.config.poll_interval = 3
9
9
 
10
10
  # Maximum batch size
11
11
  config_accessor :max_batch_size
12
- self.config.max_batch_size = 500
12
+ self.config.max_batch_size = 1000
13
13
 
14
- # Batch queue lock timeout (set during flush)
14
+ # Batch queue flush lock timeout
15
15
  config_accessor :lock_ttl
16
16
  self.config.lock_ttl = 1
17
17
  end
@@ -6,7 +6,7 @@ module Sidekiq
6
6
  options = worker_class.get_sidekiq_options
7
7
 
8
8
  batch =
9
- options.keys.include?('batch_size') ||
9
+ options.keys.include?('batch_flush_size') ||
10
10
  options.keys.include?('batch_flush_interval')
11
11
 
12
12
  passthrough =
@@ -25,8 +25,12 @@ module Sidekiq
25
25
  end
26
26
 
27
27
  private
28
+
28
29
  def add_to_batch(worker_class, queue, msg, redis_pool = nil)
29
- Sidekiq::Grouping::Batch.new(worker_class.name, queue, redis_pool).add(msg['args'])
30
+ Sidekiq::Grouping::Batch
31
+ .new(worker_class.name, queue, redis_pool)
32
+ .add(msg['args'])
33
+
30
34
  nil
31
35
  end
32
36
  end
@@ -4,10 +4,17 @@ module Sidekiq
4
4
  class << self
5
5
  include Sidekiq::Grouping::Logging
6
6
 
7
+ if Celluloid::VERSION >= '0.17'
8
+ def run!
9
+ info 'Sidekiq::Grouping starts supervision'
10
+ Sidekiq::Grouping::Actor.supervise as: :sidekiq_grouping
11
+ end
12
+ else
7
13
  def run!
8
14
  info 'Sidekiq::Grouping starts supervision'
9
15
  Sidekiq::Grouping::Actor.supervise_as(:sidekiq_grouping)
10
16
  end
17
+ end
11
18
  end
12
19
  end
13
20
  end
@@ -1,5 +1,5 @@
1
1
  module Sidekiq
2
2
  module Grouping
3
- VERSION = '0.0.6'
3
+ VERSION = '1.0.1'
4
4
  end
5
5
  end
@@ -65,9 +65,9 @@ describe Sidekiq::Grouping::Batch do
65
65
  batch = subject.new(BatchedSizeWorker.name, 'batched_size')
66
66
 
67
67
  expect(batch.could_flush?).to be_falsy
68
- 10.times { BatchedSizeWorker.perform_async('bar') }
68
+ 10.times { |n| BatchedSizeWorker.perform_async("bar#{n}") }
69
69
  batch.flush
70
- expect(BatchedSizeWorker).to have_enqueued_job([["bar"], ["bar"], ["bar"]])
70
+ expect(BatchedSizeWorker).to have_enqueued_job([["bar0"], ["bar1"]])
71
71
  expect(batch.size).to eq(7)
72
72
  end
73
73
  end
@@ -21,6 +21,7 @@ Sidekiq.logger = nil
21
21
 
22
22
  RSpec::Sidekiq.configure do |config|
23
23
  config.clear_all_enqueued_jobs = true
24
+ config.warn_when_jobs_not_processed_by_sidekiq = false
24
25
  end
25
26
 
26
27
  RSpec.configure do |config|
@@ -8,7 +8,7 @@ end
8
8
  class BatchedSizeWorker
9
9
  include Sidekiq::Worker
10
10
 
11
- sidekiq_options queue: :batched_size, batch_size: 3
11
+ sidekiq_options queue: :batched_size, batch_flush_size: 3, batch_size: 2
12
12
 
13
13
  def perform(foo)
14
14
  end
@@ -26,7 +26,9 @@ end
26
26
  class BatchedBothWorker
27
27
  include Sidekiq::Worker
28
28
 
29
- sidekiq_options queue: :batched_both, batch_flush_interval: 3600, batch_size: 3
29
+ sidekiq_options(
30
+ queue: :batched_both, batch_flush_interval: 3600, batch_flush_size: 3
31
+ )
30
32
 
31
33
  def perform(foo)
32
34
  end
@@ -35,7 +37,9 @@ end
35
37
  class BatchedUniqueArgsWorker
36
38
  include Sidekiq::Worker
37
39
 
38
- sidekiq_options queue: :batched_unique_args, batch_size: 3, batch_unique: true
40
+ sidekiq_options(
41
+ queue: :batched_unique_args, batch_flush_size: 3, batch_unique: true
42
+ )
39
43
 
40
44
  def perform(foo)
41
45
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sidekiq-grouping
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.6
4
+ version: 1.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Sokolov
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-24 00:00:00.000000000 Z
11
+ date: 2015-11-11 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -186,7 +186,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
186
186
  version: '0'
187
187
  requirements: []
188
188
  rubyforge_project:
189
- rubygems_version: 2.4.3
189
+ rubygems_version: 2.4.8
190
190
  signing_key:
191
191
  specification_version: 4
192
192
  summary: Allows identical sidekiq jobs to be processed with a single background call