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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 4d6ec140cc691fd53ceb5d495add6e3a76ce6a7b6daf2bfbde982e6e40a19987
4
- data.tar.gz: 66911fc7ec1a54e38aaaca160ee455b2463f1888ecbbf981c64a17e9d790c1a2
3
+ metadata.gz: 131525481d493d4765a33fa9b5d34524f74f221b05399b1a39b2cc47d439aa65
4
+ data.tar.gz: 4483fe6f6e98e45579d65362c2ba3f0298303522d103647c0a3d04085580af16
5
5
  SHA512:
6
- metadata.gz: 240a6603023b3edc79b69d1793e8805e86ec298f2927df7bd3a1342ad241fb3a0b619a6aa50266348003c20f751fdd58dc91a68dead319916ca351a09bee5f0f
7
- data.tar.gz: 4af1937daa29fab5f2fd818f22a64bea90d35074a0ca70109e4a36cbaa754fae199799167385f78579a854152563c1e8074c6ff91ad931e544b20c67bf7de054
6
+ metadata.gz: 9a5e357a59d77faa86eaa54552f19b2ad06b82af8a72bc80a2c66fd8ba56584391c08878c0e0b16cf32df6e6dc564d01bf60b0c16b2bcafe7649b6522643db48
7
+ data.tar.gz: 056e815c2beed08ca7e8fccc0c22afb291c849f9195b1bd5d7469d22096b62a37a8a457a21eeaa949f436e034586217e3aacf4e7d6cf44e52f325c88126c8b6c
@@ -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: 3.0.0
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
- out = client.find_node(job_name, workflow_id)
129
- out.persist_and_perform_async! if out.ready_to_start?
130
- client.release_lock(workflow_id, job_name)
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Dwf
4
- VERSION = '0.1.12'
4
+ VERSION = '0.1.13'
5
5
  end
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
- node = client.find_node(job_name, parent_id)
183
- node.persist_and_perform_async! if node.ready_to_start?
184
- client.release_lock(parent_id, job_name)
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
 
@@ -170,24 +170,18 @@ describe Dwf::Client, client: true do
170
170
 
171
171
  before do
172
172
  allow(client).to receive(:set)
173
- redis.set("wf_enqueue_outgoing_jobs_#{workflow_id}-#{job_name}", 'running')
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(redis).to have_received(:set)
190
- .with("wf_enqueue_outgoing_jobs_#{workflow_id}-#{job_name}", 'running')
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
@@ -175,14 +175,10 @@ describe Dwf::Item, item: true do
175
175
  item.enqueue_outgoing_jobs
176
176
  end
177
177
 
178
- context 'outgoing jobs ready to start' do
179
- let(:started_at) { nil }
180
- it { expect(a_item).to have_received(:persist_and_perform_async!) }
181
- end
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
 
@@ -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
- context 'outgoing jobs ready to start' do
373
- let(:started_at) { nil }
374
- it { expect(item).to have_received(:persist_and_perform_async!) }
375
- end
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.12
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-10 00:00:00.000000000 Z
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