sidekiq-batch 0.1.2 → 0.1.3
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/.gitignore +1 -0
- data/Gemfile +1 -0
- data/README.md +2 -0
- data/lib/sidekiq/batch.rb +143 -39
- data/lib/sidekiq/batch/callback.rb +49 -23
- data/lib/sidekiq/batch/extension/worker.rb +15 -0
- data/lib/sidekiq/batch/middleware.rb +7 -10
- data/lib/sidekiq/batch/status.rb +10 -1
- data/lib/sidekiq/batch/version.rb +1 -1
- metadata +4 -3
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d41af0ded27d9233c6731d110bcc24d3c31a7e0f
|
4
|
+
data.tar.gz: 2a6a63c2b2bd2159cc0456970d013819344c4670
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: c297e8094b0de083870db5850dee5eacccc59cb30aa85961fd71bff9076119092b7721cf1502b9d2556372337a5d4bdb3a1bc1c2d1630d8949d06b1bc6b4a03c
|
7
|
+
data.tar.gz: 3c9d0365850379328118ed6a8f25b59a1e96c2fde7f4a7ae0ef8695024d589ba33de38d4344d321f480d2b41e74115fe8bae7d0c815efa8b55e2171f9bc5164b
|
data/.gitignore
CHANGED
data/Gemfile
CHANGED
data/README.md
CHANGED
@@ -4,6 +4,8 @@
|
|
4
4
|
|
5
5
|
# Sidekiq::Batch
|
6
6
|
|
7
|
+
[](https://gitter.im/breamware/sidekiq-batch?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
8
|
+
|
7
9
|
[][gem]
|
8
10
|
[][travis]
|
9
11
|
[][codeclimate]
|
data/lib/sidekiq/batch.rb
CHANGED
@@ -12,16 +12,15 @@ module Sidekiq
|
|
12
12
|
|
13
13
|
BID_EXPIRE_TTL = 108_000
|
14
14
|
|
15
|
-
attr_reader :bid, :description, :callback_queue
|
15
|
+
attr_reader :bid, :description, :callback_queue, :created_at
|
16
16
|
|
17
17
|
def initialize(existing_bid = nil)
|
18
18
|
@bid = existing_bid || SecureRandom.urlsafe_base64(10)
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
end
|
19
|
+
@existing = !(!existing_bid || existing_bid.empty?) # Basically existing_bid.present?
|
20
|
+
@initialized = false
|
21
|
+
@created_at = Time.now.utc.to_f
|
22
|
+
@bidkey = "BID-" + @bid.to_s
|
23
|
+
@ready_to_queue = []
|
25
24
|
end
|
26
25
|
|
27
26
|
def description=(description)
|
@@ -36,11 +35,14 @@ module Sidekiq
|
|
36
35
|
|
37
36
|
def on(event, callback, options = {})
|
38
37
|
return unless %w(success complete).include?(event.to_s)
|
38
|
+
callback_key = "#{@bidkey}-callbacks-#{event}"
|
39
39
|
Sidekiq.redis do |r|
|
40
40
|
r.multi do
|
41
|
-
r.
|
42
|
-
|
43
|
-
|
41
|
+
r.sadd(callback_key, JSON.unparse({
|
42
|
+
callback: callback,
|
43
|
+
opts: options
|
44
|
+
}))
|
45
|
+
r.expire(callback_key, BID_EXPIRE_TTL)
|
44
46
|
end
|
45
47
|
end
|
46
48
|
end
|
@@ -48,11 +50,82 @@ module Sidekiq
|
|
48
50
|
def jobs
|
49
51
|
raise NoBlockGivenError unless block_given?
|
50
52
|
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
53
|
+
bid_data, Thread.current[:bid_data] = Thread.current[:bid_data], []
|
54
|
+
|
55
|
+
begin
|
56
|
+
if !@existing && !@initialized
|
57
|
+
parent_bid = Thread.current[:bid].bid if Thread.current[:bid]
|
58
|
+
|
59
|
+
Sidekiq.redis do |r|
|
60
|
+
r.multi do
|
61
|
+
r.hset(@bidkey, "created_at", @created_at)
|
62
|
+
r.hset(@bidkey, "parent_bid", parent_bid.to_s) if parent_bid
|
63
|
+
r.expire(@bidkey, BID_EXPIRE_TTL)
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
@initialized = true
|
68
|
+
end
|
69
|
+
|
70
|
+
@ready_to_queue = []
|
71
|
+
|
72
|
+
begin
|
73
|
+
parent = Thread.current[:bid]
|
74
|
+
Thread.current[:bid] = self
|
75
|
+
yield
|
76
|
+
ensure
|
77
|
+
Thread.current[:bid] = parent
|
78
|
+
end
|
79
|
+
|
80
|
+
return [] if @ready_to_queue.size == 0
|
81
|
+
|
82
|
+
Sidekiq.redis do |r|
|
83
|
+
r.multi do
|
84
|
+
if parent_bid
|
85
|
+
r.hincrby("BID-#{parent_bid}", "children", 1)
|
86
|
+
r.expire("BID-#{parent_bid}", BID_EXPIRE_TTL)
|
87
|
+
end
|
88
|
+
|
89
|
+
r.hincrby(@bidkey, "pending", @ready_to_queue.size)
|
90
|
+
r.hincrby(@bidkey, "total", @ready_to_queue.size)
|
91
|
+
r.expire(@bidkey, BID_EXPIRE_TTL)
|
92
|
+
|
93
|
+
r.sadd(@bidkey + "-jids", @ready_to_queue)
|
94
|
+
r.expire(@bidkey + "-jids", BID_EXPIRE_TTL)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
@ready_to_queue
|
99
|
+
ensure
|
100
|
+
Thread.current[:bid_data] = bid_data
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def increment_job_queue(jid)
|
105
|
+
@ready_to_queue << jid
|
106
|
+
end
|
107
|
+
|
108
|
+
def invalidate_all
|
109
|
+
Sidekiq.redis do |r|
|
110
|
+
r.setex("invalidated-bid-#{bid}", BID_EXPIRE_TTL, 1)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
def parent_bid
|
115
|
+
Sidekiq.redis do |r|
|
116
|
+
r.hget(@bidkey, "parent_bid")
|
117
|
+
end
|
118
|
+
end
|
119
|
+
|
120
|
+
def parent
|
121
|
+
if parent_bid
|
122
|
+
Sidekiq::Batch.new(parent_bid)
|
123
|
+
end
|
124
|
+
end
|
125
|
+
|
126
|
+
def valid?(batch = self)
|
127
|
+
valid = !Sidekiq.redis { |r| r.exists("invalidated-bid-#{batch.bid}") }
|
128
|
+
batch.parent ? valid && valid?(batch.parent) : valid
|
56
129
|
end
|
57
130
|
|
58
131
|
private
|
@@ -60,57 +133,88 @@ module Sidekiq
|
|
60
133
|
def persist_bid_attr(attribute, value)
|
61
134
|
Sidekiq.redis do |r|
|
62
135
|
r.multi do
|
63
|
-
r.hset(
|
64
|
-
r.expire(
|
136
|
+
r.hset(@bidkey, attribute, value)
|
137
|
+
r.expire(@bidkey, BID_EXPIRE_TTL)
|
65
138
|
end
|
66
139
|
end
|
67
140
|
end
|
68
141
|
|
69
142
|
class << self
|
70
143
|
def process_failed_job(bid, jid)
|
71
|
-
|
144
|
+
_, pending, failed, children, complete = Sidekiq.redis do |r|
|
72
145
|
r.multi do
|
73
146
|
r.sadd("BID-#{bid}-failed", jid)
|
147
|
+
|
148
|
+
r.hincrby("BID-#{bid}", "pending", 0)
|
74
149
|
r.scard("BID-#{bid}-failed")
|
75
|
-
r.
|
150
|
+
r.hincrby("BID-#{bid}", "children", 0)
|
151
|
+
r.scard("BID-#{bid}-complete")
|
152
|
+
|
76
153
|
r.expire("BID-#{bid}-failed", BID_EXPIRE_TTL)
|
77
154
|
end
|
78
155
|
end
|
79
|
-
|
80
|
-
|
81
|
-
end
|
156
|
+
|
157
|
+
enqueue_callbacks(:complete, bid) if pending.to_i == failed.to_i && children == complete
|
82
158
|
end
|
83
159
|
|
84
|
-
def process_successful_job(bid)
|
85
|
-
|
160
|
+
def process_successful_job(bid, jid)
|
161
|
+
failed, pending, children, complete, success, total, parent_bid = Sidekiq.redis do |r|
|
86
162
|
r.multi do
|
87
|
-
r.hincrby("BID-#{bid}", 'to_process', -1)
|
88
163
|
r.scard("BID-#{bid}-failed")
|
89
|
-
r.hincrby("BID-#{bid}",
|
164
|
+
r.hincrby("BID-#{bid}", "pending", -1)
|
165
|
+
r.hincrby("BID-#{bid}", "children", 0)
|
166
|
+
r.scard("BID-#{bid}-complete")
|
167
|
+
r.scard("BID-#{bid}-success")
|
168
|
+
r.hget("BID-#{bid}", "total")
|
169
|
+
r.hget("BID-#{bid}", "parent_bid")
|
170
|
+
|
171
|
+
r.srem("BID-#{bid}-failed", jid)
|
172
|
+
r.srem("BID-#{bid}-jids", jid)
|
90
173
|
r.expire("BID-#{bid}", BID_EXPIRE_TTL)
|
91
174
|
end
|
92
175
|
end
|
93
176
|
|
94
177
|
puts "processed process_successful_job"
|
95
|
-
|
96
|
-
|
178
|
+
|
179
|
+
enqueue_callbacks(:complete, bid) if pending.to_i == failed.to_i && children == complete
|
180
|
+
enqueue_callbacks(:success, bid) if pending.to_i.zero? && children == success
|
97
181
|
end
|
98
182
|
|
99
|
-
def
|
100
|
-
|
101
|
-
|
102
|
-
|
183
|
+
def enqueue_callbacks(event, bid)
|
184
|
+
batch_key = "BID-#{bid}"
|
185
|
+
callback_key = "#{batch_key}-callbacks-#{event}"
|
186
|
+
needed, _, callbacks, queue, parent_bid = Sidekiq.redis do |r|
|
187
|
+
r.multi do
|
188
|
+
r.hget(batch_key, event)
|
189
|
+
r.hset(batch_key, event, true)
|
190
|
+
r.smembers(callback_key)
|
191
|
+
r.hget(batch_key, "callback_queue")
|
192
|
+
r.hget(batch_key, "parent_bid")
|
193
|
+
end
|
194
|
+
end
|
195
|
+
return if needed == 'true'
|
196
|
+
|
197
|
+
begin
|
198
|
+
parent_bid = !parent_bid || parent_bid.empty? ? nil : parent_bid # Basically parent_bid.blank?
|
199
|
+
Sidekiq::Client.push_bulk(
|
200
|
+
'class' => Sidekiq::Batch::Callback::Worker,
|
201
|
+
'args' => callbacks.reduce([]) do |memo, jcb|
|
202
|
+
cb = Sidekiq.load_json(jcb)
|
203
|
+
memo << [cb['callback'], event, cb['opts'], bid, parent_bid]
|
204
|
+
end,
|
205
|
+
'queue' => queue ||= 'default'
|
206
|
+
) unless callbacks.empty?
|
207
|
+
ensure
|
208
|
+
cleanup_redis(bid) if event == :success
|
103
209
|
end
|
104
210
|
end
|
105
211
|
|
106
|
-
def
|
212
|
+
def cleanup_redis(bid)
|
107
213
|
Sidekiq.redis do |r|
|
108
|
-
r.
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
r.expire("BID-#{bid}", BID_EXPIRE_TTL)
|
113
|
-
end
|
214
|
+
r.del("BID-#{bid}",
|
215
|
+
"BID-#{bid}-callbacks-complete",
|
216
|
+
"BID-#{bid}-callbacks-success",
|
217
|
+
"BID-#{bid}-failed")
|
114
218
|
end
|
115
219
|
end
|
116
220
|
end
|
@@ -4,38 +4,64 @@ module Sidekiq
|
|
4
4
|
class Worker
|
5
5
|
include Sidekiq::Worker
|
6
6
|
|
7
|
-
def perform(clazz, event, opts, bid)
|
7
|
+
def perform(clazz, event, opts, bid, parent_bid)
|
8
8
|
return unless %w(success complete).include?(event)
|
9
9
|
clazz, method = clazz.split("#") if (clazz.class == String && clazz.include?("#"))
|
10
10
|
method = "on_#{event}" if method.nil?
|
11
|
-
|
11
|
+
status = Sidekiq::Batch::Status.new(bid)
|
12
|
+
clazz.constantize.new.send(method, status, opts) rescue nil
|
13
|
+
|
14
|
+
send(event.to_sym, bid, status, parent_bid)
|
12
15
|
end
|
13
|
-
end
|
14
16
|
|
15
|
-
|
16
|
-
def
|
17
|
-
|
18
|
-
|
19
|
-
r.
|
20
|
-
|
17
|
+
|
18
|
+
def success(bid, status, parent_bid)
|
19
|
+
if (parent_bid)
|
20
|
+
_, _, success, pending, children = Sidekiq.redis do |r|
|
21
|
+
r.multi do
|
22
|
+
r.sadd("BID-#{parent_bid}-success", bid)
|
23
|
+
r.expire("BID-#{parent_bid}-success", Sidekiq::Batch::BID_EXPIRE_TTL)
|
24
|
+
r.scard("BID-#{parent_bid}-success")
|
25
|
+
r.hincrby("BID-#{parent_bid}", "pending", 0)
|
26
|
+
r.hincrby("BID-#{parent_bid}", "children", 0)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
Batch.enqueue_callbacks(:success, parent_bid) if pending.to_i.zero? && children == success
|
31
|
+
end
|
32
|
+
|
33
|
+
Sidekiq.redis do |r|
|
34
|
+
r.del "BID-#{bid}-success", "BID-#{bid}-complete", "BID-#{bid}-jids", "BID-#{bid}-failed"
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def complete(bid, status, parent_bid)
|
39
|
+
if (parent_bid)
|
40
|
+
_, complete, pending, children, failure = Sidekiq.redis do |r|
|
41
|
+
r.multi do
|
42
|
+
r.sadd("BID-#{parent_bid}-complete", bid)
|
43
|
+
r.scard("BID-#{parent_bid}-complete")
|
44
|
+
r.hincrby("BID-#{parent_bid}", "pending", 0)
|
45
|
+
r.hincrby("BID-#{parent_bid}", "children", 0)
|
46
|
+
r.hlen("BID-#{parent_bid}-failed")
|
47
|
+
end
|
21
48
|
end
|
49
|
+
|
50
|
+
Batch.enqueue_callbacks(:complete, parent_bid) if complete == children && pending == failure
|
22
51
|
end
|
23
|
-
|
24
|
-
|
25
|
-
r.
|
26
|
-
|
27
|
-
|
52
|
+
|
53
|
+
pending, children, success = Sidekiq.redis do |r|
|
54
|
+
r.multi do
|
55
|
+
r.hincrby("BID-#{bid}", "pending", 0)
|
56
|
+
r.hincrby("BID-#{bid}", "children", 0)
|
57
|
+
r.scard("BID-#{bid}-success")
|
58
|
+
end
|
28
59
|
end
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
queue ||= 'default'
|
33
|
-
Sidekiq::Client.push('class' => Sidekiq::Batch::Callback::Worker,
|
34
|
-
'args' => [callback, event, opts, bid],
|
35
|
-
'queue' => queue)
|
36
|
-
ensure
|
37
|
-
Sidekiq::Batch.cleanup_redis(bid) if event == :success
|
60
|
+
|
61
|
+
Batch.enqueue_callbacks(:success, bid) if pending.to_i.zero? && children == success
|
62
|
+
|
38
63
|
end
|
64
|
+
|
39
65
|
end
|
40
66
|
end
|
41
67
|
end
|
@@ -1,10 +1,12 @@
|
|
1
|
+
require_relative 'extension/worker'
|
2
|
+
|
1
3
|
module Sidekiq
|
2
4
|
class Batch
|
3
5
|
module Middleware
|
4
6
|
class ClientMiddleware
|
5
7
|
def call(_worker, msg, _queue, _redis_pool = nil)
|
6
|
-
if (
|
7
|
-
|
8
|
+
if (batch = Thread.current[:bid])
|
9
|
+
batch.increment_job_queue(msg['jid']) if (msg[:bid] = batch.bid)
|
8
10
|
end
|
9
11
|
yield
|
10
12
|
end
|
@@ -14,10 +16,10 @@ module Sidekiq
|
|
14
16
|
def call(_worker, msg, _queue)
|
15
17
|
if (bid = msg['bid'])
|
16
18
|
begin
|
17
|
-
Thread.current[:bid] = bid
|
19
|
+
Thread.current[:bid] = Sidekiq::Batch.new(bid)
|
18
20
|
yield
|
19
21
|
Thread.current[:bid] = nil
|
20
|
-
Batch.process_successful_job(bid)
|
22
|
+
Batch.process_successful_job(bid, msg['jid'])
|
21
23
|
rescue
|
22
24
|
Batch.process_failed_job(bid, msg['jid'])
|
23
25
|
raise
|
@@ -44,12 +46,7 @@ module Sidekiq
|
|
44
46
|
chain.add Sidekiq::Batch::Middleware::ServerMiddleware
|
45
47
|
end
|
46
48
|
end
|
47
|
-
Sidekiq::Worker.send(:
|
48
|
-
Thread.current[:bid]
|
49
|
-
end
|
50
|
-
Sidekiq::Worker.send(:define_method, 'batch') do
|
51
|
-
Sidekiq::Batch.new(Thread.current[:bid]) if Thread.current[:bid]
|
52
|
-
end
|
49
|
+
Sidekiq::Worker.send(:include, Sidekiq::Batch::Extension::Worker)
|
53
50
|
end
|
54
51
|
end
|
55
52
|
end
|
data/lib/sidekiq/batch/status.rb
CHANGED
@@ -27,6 +27,10 @@ module Sidekiq
|
|
27
27
|
Sidekiq.redis { |r| r.hget("BID-#{bid}", 'total') }.to_i
|
28
28
|
end
|
29
29
|
|
30
|
+
def parent_bid
|
31
|
+
Sidekiq.redis { |r| r.hget("BID-#{bid}", "parent_bid") }
|
32
|
+
end
|
33
|
+
|
30
34
|
def failure_info
|
31
35
|
Sidekiq.redis { |r| r.smembers("BID-#{bid}-failed") } || []
|
32
36
|
end
|
@@ -35,6 +39,10 @@ module Sidekiq
|
|
35
39
|
'true' == Sidekiq.redis { |r| r.hget("BID-#{bid}", 'complete') }
|
36
40
|
end
|
37
41
|
|
42
|
+
def child_count
|
43
|
+
Sidekiq.redis { |r| r.hget("BID-#{bid}", 'children') }.to_i
|
44
|
+
end
|
45
|
+
|
38
46
|
def data
|
39
47
|
{
|
40
48
|
total: total,
|
@@ -42,7 +50,8 @@ module Sidekiq
|
|
42
50
|
pending: pending,
|
43
51
|
created_at: created_at,
|
44
52
|
complete: complete?,
|
45
|
-
failure_info: failure_info
|
53
|
+
failure_info: failure_info,
|
54
|
+
parent_bid: parent_bid
|
46
55
|
}
|
47
56
|
end
|
48
57
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: sidekiq-batch
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Marcin Naglik
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-05-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: sidekiq
|
@@ -97,6 +97,7 @@ files:
|
|
97
97
|
- Rakefile
|
98
98
|
- lib/sidekiq/batch.rb
|
99
99
|
- lib/sidekiq/batch/callback.rb
|
100
|
+
- lib/sidekiq/batch/extension/worker.rb
|
100
101
|
- lib/sidekiq/batch/middleware.rb
|
101
102
|
- lib/sidekiq/batch/status.rb
|
102
103
|
- lib/sidekiq/batch/version.rb
|
@@ -121,7 +122,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
121
122
|
version: '0'
|
122
123
|
requirements: []
|
123
124
|
rubyforge_project:
|
124
|
-
rubygems_version: 2.5.
|
125
|
+
rubygems_version: 2.5.2
|
125
126
|
signing_key:
|
126
127
|
specification_version: 4
|
127
128
|
summary: Sidekiq Batch Jobs
|