sidekiq-batch 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
[![Join the chat at https://gitter.im/breamware/sidekiq-batch](https://badges.gitter.im/breamware/sidekiq-batch.svg)](https://gitter.im/breamware/sidekiq-batch?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
|
8
|
+
|
7
9
|
[![Gem Version](https://badge.fury.io/rb/sidekiq-batch.svg)][gem]
|
8
10
|
[![Build Status](https://travis-ci.org/breamware/sidekiq-batch.svg?branch=master)][travis]
|
9
11
|
[![Code Climate](https://codeclimate.com/github/breamware/sidekiq-batch/badges/gpa.svg)][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
|