sidekiq-bulk 0.0.2 → 0.1
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 +4 -4
- data/README.md +35 -2
- data/lib/sidekiq/bulk.rb +9 -1
- data/sidekiq-bulk.gemspec +2 -1
- data/spec/examples.txt +21 -8
- data/spec/sidekiq_bulk_spec.rb +103 -22
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 6e466d4ca76140df65784cbe9c529e50c506e806
|
4
|
+
data.tar.gz: b56858162f9045a52b429ab18a42a052be4f5267
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9789acdf3dd12f7113bd2edeeafe57d63d9f2920b6a5072728d0e8bad8c6439adf2cacba9fe1457acab521ac66cd88b165169f858989d8e0d44fc580ea13c4ae
|
7
|
+
data.tar.gz: 30fd6e17e8893ab0fcf2ec6367114ad8a18ab00db4643fa117c8a3b3480be7a6a7d12f729da245a5dea67fe285162952218765d7a8babd7f84db8828ab6ea320
|
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# sidekiq-bulk
|
2
2
|
|
3
|
-
[](https://travis-ci.org/aprescott/sidekiq-bulk)
|
3
|
+
[](https://travis-ci.org/aprescott/sidekiq-bulk) [](https://codeclimate.com/github/aprescott/sidekiq-bulk)
|
4
4
|
|
5
5
|
Give your workers more to do!
|
6
6
|
|
@@ -11,7 +11,7 @@ Sidekiq comes with `Sidekiq::Client.push_bulk` which can be faster than `perform
|
|
11
11
|
This gem provides a wrapper around `Sidekiq::Client.push_bulk` so that instead of
|
12
12
|
|
13
13
|
```ruby
|
14
|
-
Sidekiq::Client.push_bulk("class" => FooJob, "args" => [[1], [2], [3])
|
14
|
+
Sidekiq::Client.push_bulk("class" => FooJob, "args" => [[1], [2], [3]])
|
15
15
|
```
|
16
16
|
|
17
17
|
You can write
|
@@ -67,6 +67,39 @@ all_users.each do |user|
|
|
67
67
|
end
|
68
68
|
```
|
69
69
|
|
70
|
+
## Job count splitting
|
71
|
+
|
72
|
+
`push_bulk` will only enqueue at most 10,000 jobs at a time. That is, if `items` has 20,000 elements, `push_bulk(items)` will push the first 10,000, then the second 20,000. You can control the threshold with `limit:`.
|
73
|
+
|
74
|
+
```ruby
|
75
|
+
# push in groups of 50,000 jobs at a time
|
76
|
+
FooJob.push_bulk(items, limit: 50_000)
|
77
|
+
|
78
|
+
# equivalent to FooJob.push_bulk(items, limit: 10_000)
|
79
|
+
FooJob.push_bulk(items)
|
80
|
+
```
|
81
|
+
|
82
|
+
This also works with a block.
|
83
|
+
|
84
|
+
```ruby
|
85
|
+
# this results in 5 pushes
|
86
|
+
|
87
|
+
users.length # => 100_000
|
88
|
+
FooJob.push_bulk(users, limit: 20_000) do |user|
|
89
|
+
[user.id, "some-value"]
|
90
|
+
end
|
91
|
+
```
|
92
|
+
|
93
|
+
And to disable push splitting, use `push_bulk!`.
|
94
|
+
|
95
|
+
```ruby
|
96
|
+
# one single push of 500,000 jobs, no splitting
|
97
|
+
|
98
|
+
FooJob.push_bulk!(users) do |user|
|
99
|
+
[user.id, "some-value"]
|
100
|
+
end
|
101
|
+
```
|
102
|
+
|
70
103
|
### License
|
71
104
|
|
72
105
|
Copyright (c) 2015 Adam Prescott, licensed under the MIT license. See LICENSE.
|
data/lib/sidekiq/bulk.rb
CHANGED
@@ -1,5 +1,13 @@
|
|
1
|
+
require "active_support/core_ext/array/grouping"
|
2
|
+
|
1
3
|
module SidekiqBulk
|
2
|
-
def push_bulk(items, &block)
|
4
|
+
def push_bulk(items, limit: 10_000, &block)
|
5
|
+
items.in_groups_of(limit, false).each do |group|
|
6
|
+
push_bulk!(group, &block)
|
7
|
+
end
|
8
|
+
end
|
9
|
+
|
10
|
+
def push_bulk!(items, &block)
|
3
11
|
if block
|
4
12
|
args = items.map(&block)
|
5
13
|
else
|
data/sidekiq-bulk.gemspec
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Gem::Specification.new do |s|
|
2
2
|
s.name = "sidekiq-bulk"
|
3
|
-
s.version = "0.
|
3
|
+
s.version = "0.1"
|
4
4
|
s.authors = ["Adam Prescott"]
|
5
5
|
s.email = ["adam@aprescott.com"]
|
6
6
|
s.homepage = "https://github.com/aprescott/sidekiq-bulk"
|
@@ -13,6 +13,7 @@ Gem::Specification.new do |s|
|
|
13
13
|
s.licenses = ["MIT"]
|
14
14
|
|
15
15
|
s.add_dependency("sidekiq")
|
16
|
+
s.add_dependency("activesupport")
|
16
17
|
s.add_development_dependency("rspec", ">= 3.3")
|
17
18
|
s.add_development_dependency("rspec-sidekiq")
|
18
19
|
s.add_development_dependency("pry-byebug")
|
data/spec/examples.txt
CHANGED
@@ -1,8 +1,21 @@
|
|
1
|
-
example_id
|
2
|
-
|
3
|
-
./spec/sidekiq_bulk_spec.rb[1:1]
|
4
|
-
./spec/sidekiq_bulk_spec.rb[1:2]
|
5
|
-
./spec/sidekiq_bulk_spec.rb[1:3]
|
6
|
-
./spec/sidekiq_bulk_spec.rb[1:4]
|
7
|
-
./spec/sidekiq_bulk_spec.rb[1:5]
|
8
|
-
./spec/sidekiq_bulk_spec.rb[1:6
|
1
|
+
example_id | status | run_time |
|
2
|
+
-------------------------------------- | ------ | --------------- |
|
3
|
+
./spec/sidekiq_bulk_spec.rb[1:1:1] | passed | 0.00012 seconds |
|
4
|
+
./spec/sidekiq_bulk_spec.rb[1:1:2] | passed | 0.00047 seconds |
|
5
|
+
./spec/sidekiq_bulk_spec.rb[1:1:3] | passed | 0.00036 seconds |
|
6
|
+
./spec/sidekiq_bulk_spec.rb[1:1:4] | passed | 0.00037 seconds |
|
7
|
+
./spec/sidekiq_bulk_spec.rb[1:1:5] | passed | 0.00035 seconds |
|
8
|
+
./spec/sidekiq_bulk_spec.rb[1:1:6] | passed | 0.00074 seconds |
|
9
|
+
./spec/sidekiq_bulk_spec.rb[1:1:7] | passed | 0.00044 seconds |
|
10
|
+
./spec/sidekiq_bulk_spec.rb[1:1:8] | passed | 0.00139 seconds |
|
11
|
+
./spec/sidekiq_bulk_spec.rb[1:1:9:1:1] | passed | 0.00193 seconds |
|
12
|
+
./spec/sidekiq_bulk_spec.rb[1:1:9:2:1] | passed | 0.00221 seconds |
|
13
|
+
./spec/sidekiq_bulk_spec.rb[1:1:9:3:1] | passed | 0.01202 seconds |
|
14
|
+
./spec/sidekiq_bulk_spec.rb[1:2:1] | passed | 0.00074 seconds |
|
15
|
+
./spec/sidekiq_bulk_spec.rb[1:2:2] | passed | 0.00123 seconds |
|
16
|
+
./spec/sidekiq_bulk_spec.rb[1:2:3] | passed | 0.00047 seconds |
|
17
|
+
./spec/sidekiq_bulk_spec.rb[1:2:4] | passed | 0.00692 seconds |
|
18
|
+
./spec/sidekiq_bulk_spec.rb[1:2:5] | passed | 0.00237 seconds |
|
19
|
+
./spec/sidekiq_bulk_spec.rb[1:2:6] | passed | 0.23908 seconds |
|
20
|
+
./spec/sidekiq_bulk_spec.rb[1:3:1] | passed | 0.00145 seconds |
|
21
|
+
./spec/sidekiq_bulk_spec.rb[1:3:2] | passed | 0.00037 seconds |
|
data/spec/sidekiq_bulk_spec.rb
CHANGED
@@ -10,41 +10,122 @@ RSpec.describe SidekiqBulk do
|
|
10
10
|
class BarJob < FooJob
|
11
11
|
end
|
12
12
|
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
shared_examples "a bulk push method" do |method_name|
|
14
|
+
it "provides a push_bulk method on job classes" do
|
15
|
+
expect(FooJob).to respond_to(method_name)
|
16
|
+
end
|
16
17
|
|
17
|
-
|
18
|
-
|
18
|
+
it "enqueues the job" do
|
19
|
+
FooJob.public_send(method_name, [1, 2, 3]) { |el| [2*el, "some-value"] }
|
19
20
|
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
21
|
+
expect(FooJob.jobs.length).to eq(3)
|
22
|
+
expect(FooJob).to have_enqueued_job(2, "some-value")
|
23
|
+
expect(FooJob).to have_enqueued_job(4, "some-value")
|
24
|
+
expect(FooJob).to have_enqueued_job(6, "some-value")
|
25
|
+
end
|
26
|
+
|
27
|
+
it "goes through the Sidekiq::Client interface" do
|
28
|
+
expect(Sidekiq::Client).to receive(:push_bulk).once.with("class" => FooJob, "args" => [[1], [2], [3]])
|
25
29
|
|
26
|
-
|
27
|
-
|
30
|
+
FooJob.public_send(method_name, [1, 2, 3])
|
31
|
+
end
|
32
|
+
|
33
|
+
it "uses the correct class name for subclasses" do
|
34
|
+
expect(Sidekiq::Client).to receive(:push_bulk).once.with("class" => BarJob, "args" => [[1], [2], [3]])
|
35
|
+
|
36
|
+
BarJob.push_bulk([1, 2, 3])
|
37
|
+
end
|
28
38
|
|
29
|
-
|
39
|
+
it "defaults to the identity function with no block given" do
|
40
|
+
FooJob.public_send(method_name, [10, -6.1, "a thing"])
|
41
|
+
|
42
|
+
expect(FooJob.jobs.length).to eq(3)
|
43
|
+
expect(FooJob).to have_enqueued_job(10)
|
44
|
+
expect(FooJob).to have_enqueued_job(-6.1)
|
45
|
+
expect(FooJob).to have_enqueued_job("a thing")
|
46
|
+
end
|
30
47
|
end
|
31
48
|
|
32
|
-
|
33
|
-
|
49
|
+
describe "#push_bulk" do
|
50
|
+
include_examples "a bulk push method", :push_bulk
|
51
|
+
|
52
|
+
it "limits the size of groups" do
|
53
|
+
FooJob.push_bulk([1, 2, 3, 4, 5, 6, 7], limit: 3)
|
54
|
+
|
55
|
+
expect(FooJob.jobs.length).to eq(7)
|
56
|
+
expect(FooJob).to have_enqueued_job(1)
|
57
|
+
expect(FooJob).to have_enqueued_job(2)
|
58
|
+
expect(FooJob).to have_enqueued_job(3)
|
59
|
+
expect(FooJob).to have_enqueued_job(4)
|
60
|
+
expect(FooJob).to have_enqueued_job(5)
|
61
|
+
expect(FooJob).to have_enqueued_job(6)
|
62
|
+
expect(FooJob).to have_enqueued_job(7)
|
63
|
+
end
|
64
|
+
|
65
|
+
it "limits with the item transformation" do
|
66
|
+
allow(Sidekiq::Client).to receive(:push_bulk)
|
34
67
|
|
35
|
-
|
68
|
+
FooJob.push_bulk([1, 2, 3, 4, 5, 6, 7], limit: 4) do |item|
|
69
|
+
[2*item, "some-value"]
|
70
|
+
end
|
71
|
+
|
72
|
+
expect(Sidekiq::Client).to have_received(:push_bulk).exactly(2).times
|
73
|
+
expect(Sidekiq::Client).to have_received(:push_bulk).with("class" => FooJob, "args" => [[2, "some-value"], [4, "some-value"], [6, "some-value"], [8, "some-value"]])
|
74
|
+
expect(Sidekiq::Client).to have_received(:push_bulk).with("class" => FooJob, "args" => [[10, "some-value"], [12, "some-value"], [14, "some-value"]])
|
75
|
+
end
|
76
|
+
|
77
|
+
it "goes through the Sidekiq::Client interface" do
|
78
|
+
allow(Sidekiq::Client).to receive(:push_bulk)
|
79
|
+
|
80
|
+
FooJob.push_bulk([1, 2, 3, 4, 5, 6, 7], limit: 3)
|
81
|
+
|
82
|
+
expect(Sidekiq::Client).to have_received(:push_bulk).exactly(3).times
|
83
|
+
expect(Sidekiq::Client).to have_received(:push_bulk).with("class" => FooJob, "args" => [[1], [2], [3]])
|
84
|
+
expect(Sidekiq::Client).to have_received(:push_bulk).with("class" => FooJob, "args" => [[4], [5], [6]])
|
85
|
+
expect(Sidekiq::Client).to have_received(:push_bulk).with("class" => FooJob, "args" => [[7]])
|
86
|
+
end
|
87
|
+
|
88
|
+
context "when no limit is specified" do
|
89
|
+
let(:item_count) { 9_999 }
|
90
|
+
|
91
|
+
before do
|
92
|
+
allow(Sidekiq::Client).to receive(:push_bulk)
|
93
|
+
|
94
|
+
FooJob.push_bulk((1..item_count).to_a)
|
95
|
+
end
|
96
|
+
|
97
|
+
context "when the item count is 10,000" do
|
98
|
+
let(:item_count) { 10_000 }
|
99
|
+
|
100
|
+
specify { expect(Sidekiq::Client).to have_received(:push_bulk).exactly(1).times }
|
101
|
+
end
|
102
|
+
|
103
|
+
context "when the item count is 10,001" do
|
104
|
+
let(:item_count) { 10_001 }
|
105
|
+
|
106
|
+
specify { expect(Sidekiq::Client).to have_received(:push_bulk).exactly(2).times }
|
107
|
+
end
|
108
|
+
|
109
|
+
context "when the item count is 40,000" do
|
110
|
+
let(:item_count) { 40_000 }
|
111
|
+
|
112
|
+
specify { expect(Sidekiq::Client).to have_received(:push_bulk).exactly(4).times }
|
113
|
+
end
|
114
|
+
end
|
36
115
|
end
|
37
116
|
|
38
|
-
|
39
|
-
|
117
|
+
describe "#push_bulk!" do
|
118
|
+
include_examples "a bulk push method", :push_bulk!
|
40
119
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
120
|
+
it "does not limit the number of jobs in one push" do
|
121
|
+
expect(Sidekiq::Client).to receive(:push_bulk).once.with("class" => FooJob, "args" => (1..100_000).map { |e| [e] })
|
122
|
+
|
123
|
+
FooJob.push_bulk!((1..100_000).to_a)
|
124
|
+
end
|
45
125
|
end
|
46
126
|
|
47
127
|
describe "inline test", sidekiq: :inline do
|
48
128
|
specify { expect { FooJob.push_bulk([1, 2, 3]) }.to raise_error(RuntimeError, "1") }
|
129
|
+
specify { expect { FooJob.push_bulk!([1, 2, 3]) }.to raise_error(RuntimeError, "1") }
|
49
130
|
end
|
50
131
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-bulk
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: '0.1'
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Adam Prescott
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-07-
|
11
|
+
date: 2015-07-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sidekiq
|
@@ -24,6 +24,20 @@ dependencies:
|
|
24
24
|
- - ">="
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
27
41
|
- !ruby/object:Gem::Dependency
|
28
42
|
name: rspec
|
29
43
|
requirement: !ruby/object:Gem::Requirement
|