dwf 0.1.12 → 0.1.13
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/.github/workflows/test.yaml +5 -1
- data/CHANGELOG.md +37 -0
- data/README.md +30 -0
- data/dwf.gemspec +1 -0
- data/lib/dwf/callback.rb +3 -4
- data/lib/dwf/client.rb +6 -8
- data/lib/dwf/item.rb +8 -6
- data/lib/dwf/version.rb +1 -1
- data/lib/dwf/workflow.rb +4 -4
- data/spec/dwf/client_spec.rb +9 -15
- data/spec/dwf/item_spec.rb +4 -8
- data/spec/dwf/workflow_spec.rb +5 -11
- metadata +16 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 131525481d493d4765a33fa9b5d34524f74f221b05399b1a39b2cc47d439aa65
|
4
|
+
data.tar.gz: 4483fe6f6e98e45579d65362c2ba3f0298303522d103647c0a3d04085580af16
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 9a5e357a59d77faa86eaa54552f19b2ad06b82af8a72bc80a2c66fd8ba56584391c08878c0e0b16cf32df6e6dc564d01bf60b0c16b2bcafe7649b6522643db48
|
7
|
+
data.tar.gz: 056e815c2beed08ca7e8fccc0c22afb291c849f9195b1bd5d7469d22096b62a37a8a457a21eeaa949f436e034586217e3aacf4e7d6cf44e52f325c88126c8b6c
|
data/.github/workflows/test.yaml
CHANGED
@@ -13,12 +13,16 @@ jobs:
|
|
13
13
|
|
14
14
|
runs-on: ubuntu-latest
|
15
15
|
|
16
|
+
strategy:
|
17
|
+
matrix:
|
18
|
+
ruby-version: ["2.5", "2.6", "2.7", "3.0"]
|
19
|
+
|
16
20
|
steps:
|
17
21
|
- uses: actions/checkout@v2
|
18
22
|
- name: Set up Ruby
|
19
23
|
uses: ruby/setup-ruby@477b21f02be01bcb8030d50f37cfec92bfa615b6
|
20
24
|
with:
|
21
|
-
ruby-version:
|
25
|
+
ruby-version: ${{ matrix.ruby-version }}
|
22
26
|
- name: Install dependencies
|
23
27
|
run: bundle install
|
24
28
|
- name: Run tests
|
data/CHANGELOG.md
CHANGED
@@ -1,5 +1,42 @@
|
|
1
1
|
# Changelog
|
2
2
|
All notable changes to this project will be documented in this file.
|
3
|
+
|
4
|
+
## 0.1.12
|
5
|
+
### Added
|
6
|
+
#### Dynamic workflows
|
7
|
+
There might be a case when you have to contruct the workflow dynamically depend on the input
|
8
|
+
As an example, let's write a workflow which puts from 1 to 100 into the terminal parallely . Additionally after finish all job, it will puts the finshed word into the terminal
|
9
|
+
```ruby
|
10
|
+
class FirstMainItem < Dwf::Item
|
11
|
+
def perform
|
12
|
+
puts "#{self.class.name}: running #{params}"
|
13
|
+
end
|
14
|
+
end
|
15
|
+
|
16
|
+
SecondMainItem = Class.new(FirstMainItem)
|
17
|
+
|
18
|
+
class TestWf < Dwf::Workflow
|
19
|
+
def configure
|
20
|
+
items = (1..100).to_a.map do |number|
|
21
|
+
run FirstMainItem, params: number
|
22
|
+
end
|
23
|
+
run SecondMainItem, after: items, params: "finished"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
```
|
28
|
+
We can achieve that because run method returns the id of the created job, which we can use for chaining dependencies.
|
29
|
+
Now, when we create the workflow like this:
|
30
|
+
```ruby
|
31
|
+
wf = TestWf.create
|
32
|
+
# wf.callback_type = Dwf::Workflow::SK_BATCH
|
33
|
+
wf.start!
|
34
|
+
```
|
35
|
+
|
36
|
+
## 0.1.12
|
37
|
+
### Added
|
38
|
+
#### Subworkflow for all callback types
|
39
|
+
same with `0.1.11`
|
3
40
|
## 0.1.11
|
4
41
|
### Added
|
5
42
|
#### Subworkflow - Only support sidekiq pro
|
data/README.md
CHANGED
@@ -199,6 +199,36 @@ Main flow: ThirtItem running
|
|
199
199
|
Main flow: ThirtItem finish
|
200
200
|
```
|
201
201
|
|
202
|
+
## Dynamic workflows
|
203
|
+
There might be a case when you have to contruct the workflow dynamically depend on the input
|
204
|
+
As an example, let's write a workflow which puts from 1 to 100 into the terminal parallelly . Additionally after finish all job, it will puts the finshed word into the terminal
|
205
|
+
```ruby
|
206
|
+
class FirstMainItem < Dwf::Item
|
207
|
+
def perform
|
208
|
+
puts "#{self.class.name}: running #{params}"
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
SecondMainItem = Class.new(FirstMainItem)
|
213
|
+
|
214
|
+
class TestWf < Dwf::Workflow
|
215
|
+
def configure
|
216
|
+
items = (1..100).to_a.map do |number|
|
217
|
+
run FirstMainItem, params: number
|
218
|
+
end
|
219
|
+
run SecondMainItem, after: items, params: "finished"
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
```
|
224
|
+
We can achieve that because run method returns the id of the created job, which we can use for chaining dependencies.
|
225
|
+
Now, when we create the workflow like this:
|
226
|
+
```ruby
|
227
|
+
wf = TestWf.create
|
228
|
+
# wf.callback_type = Dwf::Workflow::SK_BATCH
|
229
|
+
wf.start!
|
230
|
+
```
|
231
|
+
|
202
232
|
# Todo
|
203
233
|
- [x] Make it work
|
204
234
|
- [x] Support pass params
|
data/dwf.gemspec
CHANGED
@@ -28,6 +28,7 @@ Gem::Specification.new do |spec|
|
|
28
28
|
spec.add_development_dependency 'byebug', '~> 11.1.3'
|
29
29
|
spec.add_development_dependency 'mock_redis', '~> 0.27.2'
|
30
30
|
spec.add_dependency 'redis', '~> 4.2.0'
|
31
|
+
spec.add_dependency 'redis-mutex', '~> 4.0.2'
|
31
32
|
spec.add_development_dependency 'rspec', '~> 3.2'
|
32
33
|
spec.add_dependency 'sidekiq', '~> 6.2.0'
|
33
34
|
spec.add_development_dependency 'simplecov'
|
data/lib/dwf/callback.rb
CHANGED
@@ -45,6 +45,7 @@ module Dwf
|
|
45
45
|
)
|
46
46
|
batch.jobs do
|
47
47
|
jobs.each do |job|
|
48
|
+
job.reload
|
48
49
|
job.persist_and_perform_async! if job.ready_to_start?
|
49
50
|
end
|
50
51
|
end
|
@@ -67,10 +68,8 @@ module Dwf
|
|
67
68
|
end.compact
|
68
69
|
end
|
69
70
|
|
70
|
-
def with_lock(workflow_id, job_name)
|
71
|
-
client.check_or_lock(workflow_id, job_name)
|
72
|
-
yield
|
73
|
-
client.release_lock(workflow_id, job_name)
|
71
|
+
def with_lock(workflow_id, job_name, &block)
|
72
|
+
client.check_or_lock(workflow_id, job_name, &block)
|
74
73
|
end
|
75
74
|
|
76
75
|
def start_with_batch(node)
|
data/lib/dwf/client.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require_relative 'errors'
|
2
|
+
require 'redis-mutex'
|
2
3
|
|
3
4
|
module Dwf
|
4
5
|
class Client
|
@@ -63,14 +64,9 @@ module Dwf
|
|
63
64
|
redis.hset("dwf.jobs.#{job.workflow_id}.#{job.klass}", job.id, job.as_json)
|
64
65
|
end
|
65
66
|
|
66
|
-
def check_or_lock(workflow_id, job_name)
|
67
|
+
def check_or_lock(workflow_id, job_name, &block)
|
67
68
|
key = "wf_enqueue_outgoing_jobs_#{workflow_id}-#{job_name}"
|
68
|
-
|
69
|
-
if key_exists?(key)
|
70
|
-
sleep 2
|
71
|
-
else
|
72
|
-
set(key, 'running')
|
73
|
-
end
|
69
|
+
RedisMutex.with_lock(key, sleep: 0.3, block: 2, &block)
|
74
70
|
end
|
75
71
|
|
76
72
|
def release_lock(workflow_id, job_name)
|
@@ -175,7 +171,9 @@ module Dwf
|
|
175
171
|
end
|
176
172
|
|
177
173
|
def redis
|
178
|
-
@redis ||= Redis.new(config.redis_opts)
|
174
|
+
@redis ||= Redis.new(config.redis_opts).tap do |instance|
|
175
|
+
RedisClassy.redis = instance
|
176
|
+
end
|
179
177
|
end
|
180
178
|
end
|
181
179
|
end
|
data/lib/dwf/item.rb
CHANGED
@@ -49,8 +49,8 @@ module Dwf
|
|
49
49
|
assign_attributes(item.to_hash)
|
50
50
|
end
|
51
51
|
|
52
|
-
def perform_async
|
53
|
-
Dwf::Worker.set(queue: queue || client.config.namespace)
|
52
|
+
def perform_async(options = {})
|
53
|
+
Dwf::Worker.set(options.merge(queue: queue || client.config.namespace))
|
54
54
|
.perform_async(workflow_id, name)
|
55
55
|
end
|
56
56
|
|
@@ -124,11 +124,13 @@ module Dwf
|
|
124
124
|
return workflow.enqueue_outgoing_jobs if leaf?
|
125
125
|
|
126
126
|
outgoing.each do |job_name|
|
127
|
-
client.check_or_lock(workflow_id, job_name)
|
128
|
-
|
129
|
-
|
130
|
-
|
127
|
+
client.check_or_lock(workflow_id, job_name) do
|
128
|
+
out = client.find_node(job_name, workflow_id)
|
129
|
+
out.persist_and_perform_async! if out.ready_to_start?
|
130
|
+
end
|
131
131
|
end
|
132
|
+
rescue RedisMutex::LockError
|
133
|
+
perform_async(wait: 2)
|
132
134
|
end
|
133
135
|
|
134
136
|
def to_hash
|
data/lib/dwf/version.rb
CHANGED
data/lib/dwf/workflow.rb
CHANGED
@@ -178,10 +178,10 @@ module Dwf
|
|
178
178
|
return unless sub_workflow?
|
179
179
|
|
180
180
|
outgoing.each do |job_name|
|
181
|
-
client.check_or_lock(parent_id, job_name)
|
182
|
-
|
183
|
-
|
184
|
-
|
181
|
+
client.check_or_lock(parent_id, job_name) do
|
182
|
+
node = client.find_node(job_name, parent_id)
|
183
|
+
node.persist_and_perform_async! if node.ready_to_start?
|
184
|
+
end
|
185
185
|
end
|
186
186
|
end
|
187
187
|
|
data/spec/dwf/client_spec.rb
CHANGED
@@ -170,24 +170,18 @@ describe Dwf::Client, client: true do
|
|
170
170
|
|
171
171
|
before do
|
172
172
|
allow(client).to receive(:set)
|
173
|
-
|
174
|
-
client.check_or_lock(workflow_id, job_name)
|
175
|
-
end
|
176
|
-
|
177
|
-
it { expect(client).not_to have_received(:set) }
|
178
|
-
end
|
179
|
-
|
180
|
-
context 'job is not running' do
|
181
|
-
let(:job_name) { 'ahihi' }
|
182
|
-
|
183
|
-
before do
|
184
|
-
allow(redis).to receive(:set)
|
185
|
-
client.check_or_lock(workflow_id, job_name)
|
173
|
+
allow(RedisMutex).to receive(:with_lock)
|
174
|
+
client.check_or_lock(workflow_id, job_name) {}
|
186
175
|
end
|
187
176
|
|
188
177
|
it do
|
189
|
-
expect(
|
190
|
-
.
|
178
|
+
expect(RedisMutex)
|
179
|
+
.to have_received(:with_lock)
|
180
|
+
.with(
|
181
|
+
"wf_enqueue_outgoing_jobs_#{workflow_id}-#{job_name}",
|
182
|
+
sleep: 0.3,
|
183
|
+
block: 2
|
184
|
+
)
|
191
185
|
end
|
192
186
|
end
|
193
187
|
end
|
data/spec/dwf/item_spec.rb
CHANGED
@@ -175,14 +175,10 @@ describe Dwf::Item, item: true do
|
|
175
175
|
item.enqueue_outgoing_jobs
|
176
176
|
end
|
177
177
|
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
context 'outgoing jobs havent ready to start' do
|
184
|
-
let(:started_at) { Time.now.to_i }
|
185
|
-
it { expect(a_item).not_to have_received(:persist_and_perform_async!) }
|
178
|
+
it do
|
179
|
+
expect(client_double).to have_received(:check_or_lock) do |&block|
|
180
|
+
expect(block).to be_kind_of Proc
|
181
|
+
end
|
186
182
|
end
|
187
183
|
end
|
188
184
|
|
data/spec/dwf/workflow_spec.rb
CHANGED
@@ -360,23 +360,17 @@ describe Dwf::Workflow, workflow: true do
|
|
360
360
|
let(:item) do
|
361
361
|
Dwf::Item.new(
|
362
362
|
workflow_id: SecureRandom.uuid,
|
363
|
-
id: SecureRandom.uuid
|
364
|
-
started_at: started_at
|
363
|
+
id: SecureRandom.uuid
|
365
364
|
)
|
366
365
|
end
|
367
366
|
before do
|
368
|
-
allow(item).to receive(:persist_and_perform_async!)
|
369
367
|
workflow.enqueue_outgoing_jobs
|
370
368
|
end
|
371
369
|
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
376
|
-
|
377
|
-
context 'outgoing jobs havent ready to start' do
|
378
|
-
let(:started_at) { Time.now.to_i }
|
379
|
-
it { expect(item).not_to have_received(:persist_and_perform_async!) }
|
370
|
+
it do
|
371
|
+
expect(client).to have_received(:check_or_lock) do |&block|
|
372
|
+
expect(block).to be_kind_of Proc
|
373
|
+
end
|
380
374
|
end
|
381
375
|
end
|
382
376
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: dwf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- dthtien
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2021-10-
|
11
|
+
date: 2021-10-16 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: byebug
|
@@ -52,6 +52,20 @@ dependencies:
|
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
54
|
version: 4.2.0
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: redis-mutex
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 4.0.2
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 4.0.2
|
55
69
|
- !ruby/object:Gem::Dependency
|
56
70
|
name: rspec
|
57
71
|
requirement: !ruby/object:Gem::Requirement
|