dwf 0.1.0
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 +7 -0
- data/.gitignore +6 -0
- data/.ruby-version +1 -0
- data/Gemfile +8 -0
- data/LICENSE.txt +21 -0
- data/README.md +60 -0
- data/dwf.gemspec +31 -0
- data/lib/dwf/callback.rb +67 -0
- data/lib/dwf/client.rb +100 -0
- data/lib/dwf/item.rb +153 -0
- data/lib/dwf/utils.rb +38 -0
- data/lib/dwf/worker.rb +24 -0
- data/lib/dwf/workflow.rb +169 -0
- data/lib/dwf.rb +20 -0
- metadata +113 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: ad9df2cc13b2cf7cdca6b837d6b4b1b97e3784002afd8f756f4dfd85017aa749
|
4
|
+
data.tar.gz: '0960d1ebafa201f77b56e1adb99a7df1237f0b277474f8b20815bd1617204393'
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 1ad226e5469a263d8d59214d4678ee890af48e1b20b1e6e630be9650b8a8e4b54c6b0ca96534615369f68055d9b69b3f65d3e8ee515bc118df51b22e734fd5aa
|
7
|
+
data.tar.gz: efc316c11eb6d8dfc6b38922195a9af98418a62bd5e77812620dbe7194aabdae404b0a985dacf50a104c82fb9eeb3c45ada5abe8c5b37838d6dd8e7361c4a206
|
data/.gitignore
ADDED
data/.ruby-version
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
3.0.0
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2021 dthtien
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# DSL playground
|
2
|
+
[Gush](https://github.com/chaps-io/gush) cloned without [ActiveJob](https://guides.rubyonrails.org/active_job_basics.html) but requried [Sidekiq](https://github.com/mperham/sidekiq). This project is for researching DSL purpose
|
3
|
+
|
4
|
+
# Execute flow
|
5
|
+
## Declare jobs
|
6
|
+
|
7
|
+
```ruby
|
8
|
+
require_relative './wf/item'
|
9
|
+
|
10
|
+
class A < Wf::Item
|
11
|
+
def perform
|
12
|
+
puts "#{self.class.name} Working"
|
13
|
+
sleep 2
|
14
|
+
puts "#{self.class.name} Finished"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
class E < A; end
|
19
|
+
class B < A; end
|
20
|
+
class C < E; end
|
21
|
+
class D < E; end
|
22
|
+
```
|
23
|
+
|
24
|
+
## Declare flow
|
25
|
+
```ruby
|
26
|
+
class TestWf < Wf::Workflow
|
27
|
+
def configure
|
28
|
+
run A
|
29
|
+
run B, after: A
|
30
|
+
run C, after: A
|
31
|
+
run E, after: [B, C]
|
32
|
+
run D, after: [E]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
```
|
37
|
+
|
38
|
+
### Execute flow
|
39
|
+
```ruby
|
40
|
+
wf = TestWf.create
|
41
|
+
wf.start!
|
42
|
+
```
|
43
|
+
|
44
|
+
### Output
|
45
|
+
```
|
46
|
+
A Working
|
47
|
+
A Finished
|
48
|
+
B Working
|
49
|
+
C Working
|
50
|
+
B Finished
|
51
|
+
C Finished
|
52
|
+
E Working
|
53
|
+
E Finished
|
54
|
+
D Working
|
55
|
+
D Finished
|
56
|
+
```
|
57
|
+
|
58
|
+
# References
|
59
|
+
- https://github.com/chaps-io/gush
|
60
|
+
- https://github.com/mperham/sidekiq
|
data/dwf.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
# coding: utf-8
|
3
|
+
|
4
|
+
lib = File.expand_path('../lib', __FILE__)
|
5
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
6
|
+
|
7
|
+
Gem::Specification.new do |spec|
|
8
|
+
spec.name = "dwf"
|
9
|
+
spec.version = '0.1.0'
|
10
|
+
spec.authors = ["dthtien"]
|
11
|
+
spec.email = ["tiendt2311@gmail.com"]
|
12
|
+
|
13
|
+
spec.summary = 'Gush cloned without ActiveJob but requried Sidekiq. This project is for researching DSL purpose'
|
14
|
+
spec.description = 'Workflow'
|
15
|
+
spec.homepage = 'https://github.com/dthtien/wf'
|
16
|
+
spec.license = "MIT"
|
17
|
+
spec.required_ruby_version = ">= 2.4.0"
|
18
|
+
|
19
|
+
# Specify which files should be added to the gem when it is released.
|
20
|
+
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
21
|
+
spec.files = `git ls-files -z`.split("\x0")
|
22
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
23
|
+
spec.require_paths = ["lib"]
|
24
|
+
|
25
|
+
# guide at: https://bundler.io/guides/creating_gem.html
|
26
|
+
|
27
|
+
spec.add_development_dependency 'byebug', '~> 11.1.3'
|
28
|
+
spec.add_dependency 'redis', '~> 4.2.0'
|
29
|
+
spec.add_development_dependency 'rspec', '~> 3.2'
|
30
|
+
spec.add_dependency 'sidekiq', '~> 6.2.0'
|
31
|
+
end
|
data/lib/dwf/callback.rb
ADDED
@@ -0,0 +1,67 @@
|
|
1
|
+
require 'sidekiq-pro'
|
2
|
+
require_relative 'client'
|
3
|
+
|
4
|
+
module Dwf
|
5
|
+
class Callback
|
6
|
+
def process_next_step(status, options)
|
7
|
+
previous_job_names = options['names']
|
8
|
+
workflow_id = options['workflow_id']
|
9
|
+
processing_job_names = previous_job_names.map do |job_name|
|
10
|
+
job = client.find_job(workflow_id, job_name)
|
11
|
+
job.outgoing
|
12
|
+
end.flatten.uniq
|
13
|
+
return if processing_job_names.empty?
|
14
|
+
|
15
|
+
overall = Sidekiq::Batch.new(status.parent_bid)
|
16
|
+
overall.jobs { setup_batch(processing_job_names, workflow_id) }
|
17
|
+
end
|
18
|
+
|
19
|
+
def start(job)
|
20
|
+
job.outgoing.any? ? start_with_batch(job) : job.perform_async
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def setup_batch(processing_job_names, workflow_id)
|
26
|
+
batch = Sidekiq::Batch.new
|
27
|
+
batch.on(
|
28
|
+
:success,
|
29
|
+
'Dwf::Callback#process_next_step',
|
30
|
+
names: processing_job_names,
|
31
|
+
workflow_id: workflow_id
|
32
|
+
)
|
33
|
+
|
34
|
+
batch.jobs do
|
35
|
+
processing_job_names.each { |job_name| perform_job(job_name, workflow_id) }
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def perform_job(job_name, workflow_id)
|
40
|
+
with_lock workflow_id, job_name do
|
41
|
+
job = client.find_job(workflow_id, job_name)
|
42
|
+
job.persist_and_perform_async! if job.ready_to_start?
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
def with_lock(workflow_id, job_name)
|
47
|
+
client.check_or_lock(workflow_id, job_name)
|
48
|
+
yield
|
49
|
+
client.release_lock(workflow_id, job_name)
|
50
|
+
end
|
51
|
+
|
52
|
+
def start_with_batch(job)
|
53
|
+
batch = Sidekiq::Batch.new
|
54
|
+
batch.on(
|
55
|
+
:success,
|
56
|
+
'Dwf::Callback#process_next_step',
|
57
|
+
names: [job.name],
|
58
|
+
workflow_id: job.workflow_id
|
59
|
+
)
|
60
|
+
batch.jobs { job.perform_async }
|
61
|
+
end
|
62
|
+
|
63
|
+
def client
|
64
|
+
@client ||= Dwf::Client.new
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/dwf/client.rb
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
module Dwf
|
2
|
+
class Client
|
3
|
+
def find_job(workflow_id, job_name)
|
4
|
+
job_name_match = /(?<klass>\w*[^-])-(?<identifier>.*)/.match(job_name)
|
5
|
+
data = if job_name_match
|
6
|
+
find_job_by_klass_and_id(workflow_id, job_name)
|
7
|
+
else
|
8
|
+
find_job_by_klass(workflow_id, job_name)
|
9
|
+
end
|
10
|
+
|
11
|
+
return nil if data.nil?
|
12
|
+
|
13
|
+
data = JSON.parse(data)
|
14
|
+
Dwf::Item.from_hash(Dwf::Utils.symbolize_keys(data))
|
15
|
+
end
|
16
|
+
|
17
|
+
def persist_job(job)
|
18
|
+
redis.hset("dwf.jobs.#{job.workflow_id}.#{job.klass}", job.id, job.as_json)
|
19
|
+
end
|
20
|
+
|
21
|
+
def check_or_lock(workflow_id, job_name)
|
22
|
+
key = "wf_enqueue_outgoing_jobs_#{workflow_id}-#{job_name}"
|
23
|
+
|
24
|
+
if key_exists?(key)
|
25
|
+
sleep 2
|
26
|
+
else
|
27
|
+
set(key, 'running')
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def release_lock(workflow_id, job_name)
|
32
|
+
delete("dwf_enqueue_outgoing_jobs_#{workflow_id}-#{job_name}")
|
33
|
+
end
|
34
|
+
|
35
|
+
def persist_workflow(workflow)
|
36
|
+
redis.set("dwf.workflows.#{workflow.id}", workflow.as_json)
|
37
|
+
end
|
38
|
+
|
39
|
+
def build_job_id(workflow_id, job_klass)
|
40
|
+
jid = nil
|
41
|
+
|
42
|
+
loop do
|
43
|
+
jid = SecureRandom.uuid
|
44
|
+
available = !redis.hexists(
|
45
|
+
"dwf.jobs.#{workflow_id}.#{job_klass}",
|
46
|
+
jid
|
47
|
+
)
|
48
|
+
|
49
|
+
break if available
|
50
|
+
end
|
51
|
+
|
52
|
+
jid
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_workflow_id
|
56
|
+
wid = nil
|
57
|
+
loop do
|
58
|
+
wid = SecureRandom.uuid
|
59
|
+
available = !redis.exists?("dwf.workflow.#{wid}")
|
60
|
+
|
61
|
+
break if available
|
62
|
+
end
|
63
|
+
|
64
|
+
wid
|
65
|
+
end
|
66
|
+
|
67
|
+
def key_exists?(key)
|
68
|
+
redis.exists?(key)
|
69
|
+
end
|
70
|
+
|
71
|
+
def set(key, value)
|
72
|
+
redis.set(key, value)
|
73
|
+
end
|
74
|
+
|
75
|
+
def delete(key)
|
76
|
+
redis.del(key)
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def find_job_by_klass_and_id(workflow_id, job_name)
|
82
|
+
job_klass, job_id = job_name.split('|')
|
83
|
+
|
84
|
+
redis.hget("dwf.jobs.#{workflow_id}.#{job_klass}", job_id)
|
85
|
+
end
|
86
|
+
|
87
|
+
def find_job_by_klass(workflow_id, job_name)
|
88
|
+
_new_cursor, result = redis.hscan("dwf.jobs.#{workflow_id}.#{job_name}", 0, count: 1)
|
89
|
+
return nil if result.empty?
|
90
|
+
|
91
|
+
_job_id, job = *result[0]
|
92
|
+
|
93
|
+
job
|
94
|
+
end
|
95
|
+
|
96
|
+
def redis
|
97
|
+
@redis ||= Redis.new
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
data/lib/dwf/item.rb
ADDED
@@ -0,0 +1,153 @@
|
|
1
|
+
require_relative 'client'
|
2
|
+
|
3
|
+
module Dwf
|
4
|
+
class Item
|
5
|
+
attr_reader :workflow_id, :id, :params, :queue, :klass, :started_at,
|
6
|
+
:enqueued_at, :finished_at, :failed_at
|
7
|
+
attr_accessor :incomming, :outgoing
|
8
|
+
|
9
|
+
def initialize(options = {})
|
10
|
+
@workflow_id = options[:workflow_id]
|
11
|
+
@id = options[:id]
|
12
|
+
@params = options[:params]
|
13
|
+
@queue = options[:queue] || 'default'
|
14
|
+
@incomming = options[:incoming] || []
|
15
|
+
@outgoing = options[:outgoing] || []
|
16
|
+
@klass = options[:klass] || self.class
|
17
|
+
@finished_at = options[:finished_at]
|
18
|
+
@enqueued_at = options[:enqueued_at]
|
19
|
+
@started_at = options[:started_at]
|
20
|
+
end
|
21
|
+
|
22
|
+
def self.from_hash(hash)
|
23
|
+
Module.const_get(hash[:klass]).new(hash)
|
24
|
+
end
|
25
|
+
|
26
|
+
def persist_and_perform_async!
|
27
|
+
enqueue!
|
28
|
+
persist!
|
29
|
+
perform_async
|
30
|
+
end
|
31
|
+
|
32
|
+
def perform; end
|
33
|
+
|
34
|
+
def perform_async
|
35
|
+
Dwf::Worker.set(queue: queue).perform_async(workflow_id, name)
|
36
|
+
end
|
37
|
+
|
38
|
+
def name
|
39
|
+
@name ||= "#{klass}|#{id}"
|
40
|
+
end
|
41
|
+
|
42
|
+
def no_dependencies?
|
43
|
+
incomming.empty?
|
44
|
+
end
|
45
|
+
|
46
|
+
def parents_succeeded?
|
47
|
+
incomming.all? do |name|
|
48
|
+
client.find_job(workflow_id, name).succeeded?
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def enqueue!
|
53
|
+
@enqueued_at = current_timestamp
|
54
|
+
@started_at = nil
|
55
|
+
@finished_at = nil
|
56
|
+
@failed_at = nil
|
57
|
+
end
|
58
|
+
|
59
|
+
def mark_as_started
|
60
|
+
start!
|
61
|
+
persist!
|
62
|
+
end
|
63
|
+
|
64
|
+
def mark_as_finished
|
65
|
+
finish!
|
66
|
+
persist!
|
67
|
+
end
|
68
|
+
|
69
|
+
def start!
|
70
|
+
@started_at = current_timestamp
|
71
|
+
@failed_at = nil
|
72
|
+
end
|
73
|
+
|
74
|
+
def finish!
|
75
|
+
@finished_at = current_timestamp
|
76
|
+
end
|
77
|
+
|
78
|
+
def fail!
|
79
|
+
@finished_at = @failed_at = current_timestamp
|
80
|
+
end
|
81
|
+
|
82
|
+
def enqueued?
|
83
|
+
!enqueued_at.nil?
|
84
|
+
end
|
85
|
+
|
86
|
+
def finished?
|
87
|
+
!finished_at.nil?
|
88
|
+
end
|
89
|
+
|
90
|
+
def failed?
|
91
|
+
!failed_at.nil?
|
92
|
+
end
|
93
|
+
|
94
|
+
def succeeded?
|
95
|
+
finished? && !failed?
|
96
|
+
end
|
97
|
+
|
98
|
+
def started?
|
99
|
+
!started_at.nil?
|
100
|
+
end
|
101
|
+
|
102
|
+
def running?
|
103
|
+
started? && !finished?
|
104
|
+
end
|
105
|
+
|
106
|
+
def ready_to_start?
|
107
|
+
!running? && !enqueued? && !finished? && !failed? && parents_succeeded?
|
108
|
+
end
|
109
|
+
|
110
|
+
def current_timestamp
|
111
|
+
Time.now.to_i
|
112
|
+
end
|
113
|
+
|
114
|
+
def enqueue_outgoing_jobs
|
115
|
+
outgoing.each do |job_name|
|
116
|
+
client.check_or_lock(workflow_id, job_name)
|
117
|
+
out = client.find_job(workflow_id, job_name)
|
118
|
+
out.persist_and_perform_async! if out.ready_to_start?
|
119
|
+
client.release_lock(workflow_id, job_name)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def to_hash
|
124
|
+
{
|
125
|
+
id: id,
|
126
|
+
klass: klass.to_s,
|
127
|
+
queue: queue,
|
128
|
+
incoming: incomming,
|
129
|
+
outgoing: outgoing,
|
130
|
+
finished_at: finished_at,
|
131
|
+
enqueued_at: enqueued_at,
|
132
|
+
started_at: started_at,
|
133
|
+
failed_at: failed_at,
|
134
|
+
params: params,
|
135
|
+
workflow_id: workflow_id
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
139
|
+
def as_json
|
140
|
+
to_hash.to_json
|
141
|
+
end
|
142
|
+
|
143
|
+
def persist!
|
144
|
+
client.persist_job(self)
|
145
|
+
end
|
146
|
+
|
147
|
+
private
|
148
|
+
|
149
|
+
def client
|
150
|
+
@client ||= Dwf::Client.new
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
data/lib/dwf/utils.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module Dwf
|
2
|
+
module Utils
|
3
|
+
def self.symbolize_keys(obj)
|
4
|
+
case obj
|
5
|
+
when Array
|
6
|
+
obj.inject([]) do |res, val|
|
7
|
+
res << case val
|
8
|
+
when Hash, Array
|
9
|
+
symbolize_keys(val)
|
10
|
+
else
|
11
|
+
val
|
12
|
+
end
|
13
|
+
|
14
|
+
res
|
15
|
+
end
|
16
|
+
when Hash
|
17
|
+
obj.inject({}) do |res, (key, val)|
|
18
|
+
nkey = case key
|
19
|
+
when String
|
20
|
+
key.to_sym
|
21
|
+
else
|
22
|
+
key
|
23
|
+
end
|
24
|
+
nval = case val
|
25
|
+
when Hash, Array
|
26
|
+
symbolize_keys(val)
|
27
|
+
else
|
28
|
+
val
|
29
|
+
end
|
30
|
+
res[nkey] = nval
|
31
|
+
res
|
32
|
+
end
|
33
|
+
else
|
34
|
+
obj
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/dwf/worker.rb
ADDED
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'sidekiq'
|
2
|
+
require_relative 'client'
|
3
|
+
|
4
|
+
module Dwf
|
5
|
+
class Worker
|
6
|
+
include Sidekiq::Worker
|
7
|
+
|
8
|
+
def perform(workflow_id, job_name)
|
9
|
+
job = client.find_job(workflow_id, job_name)
|
10
|
+
return job.enqueue_outgoing_jobs if job. succeeded?
|
11
|
+
|
12
|
+
job.mark_as_started
|
13
|
+
job.perform
|
14
|
+
job.mark_as_finished
|
15
|
+
# job.enqueue_outgoing_jobs
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def client
|
21
|
+
@client ||= Dwf::Client.new
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
data/lib/dwf/workflow.rb
ADDED
@@ -0,0 +1,169 @@
|
|
1
|
+
require_relative 'client'
|
2
|
+
require_relative 'worker'
|
3
|
+
require_relative 'callback'
|
4
|
+
|
5
|
+
module Dwf
|
6
|
+
class Workflow
|
7
|
+
attr_reader :dependencies, :jobs, :started_at, :finished_at, :persisted, :stopped
|
8
|
+
|
9
|
+
class << self
|
10
|
+
def create
|
11
|
+
flow = new
|
12
|
+
flow.save
|
13
|
+
flow
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize
|
18
|
+
@dependencies = []
|
19
|
+
@id = id
|
20
|
+
@jobs = []
|
21
|
+
@persisted = false
|
22
|
+
@stopped = false
|
23
|
+
|
24
|
+
setup
|
25
|
+
end
|
26
|
+
|
27
|
+
def start!
|
28
|
+
initial_jobs.each do |job|
|
29
|
+
Dwf::Callback.new.start(job)
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def save
|
34
|
+
client.persist_workflow(self)
|
35
|
+
jobs.each(&:persist!)
|
36
|
+
mark_as_persisted
|
37
|
+
true
|
38
|
+
end
|
39
|
+
|
40
|
+
def id
|
41
|
+
@id ||= client.build_workflow_id
|
42
|
+
end
|
43
|
+
|
44
|
+
def configure; end
|
45
|
+
|
46
|
+
def run(klass, options = {})
|
47
|
+
node = klass.new(
|
48
|
+
workflow_id: id,
|
49
|
+
id: client.build_job_id(id, klass.to_s),
|
50
|
+
params: options.fetch(:params, {}),
|
51
|
+
queue: options[:queue],
|
52
|
+
)
|
53
|
+
|
54
|
+
jobs << node
|
55
|
+
|
56
|
+
build_dependencies_structure(node, options)
|
57
|
+
node.name
|
58
|
+
end
|
59
|
+
|
60
|
+
def find_job(name)
|
61
|
+
match_data = /(?<klass>\w*[^-])-(?<identifier>.*)/.match(name.to_s)
|
62
|
+
|
63
|
+
if match_data.nil?
|
64
|
+
job = jobs.find { |node| node.klass.to_s == name.to_s }
|
65
|
+
else
|
66
|
+
job = jobs.find { |node| node.name.to_s == name.to_s }
|
67
|
+
end
|
68
|
+
|
69
|
+
job
|
70
|
+
end
|
71
|
+
|
72
|
+
def to_hash
|
73
|
+
name = self.class.to_s
|
74
|
+
{
|
75
|
+
name: name,
|
76
|
+
id: id,
|
77
|
+
arguments: @arguments,
|
78
|
+
total: jobs.count,
|
79
|
+
finished: jobs.count(&:finished?),
|
80
|
+
klass: name,
|
81
|
+
status: status,
|
82
|
+
stopped: stopped,
|
83
|
+
started_at: started_at,
|
84
|
+
finished_at: finished_at
|
85
|
+
}
|
86
|
+
end
|
87
|
+
|
88
|
+
def as_json
|
89
|
+
to_hash.to_json
|
90
|
+
end
|
91
|
+
|
92
|
+
def finished?
|
93
|
+
jobs.all?(&:finished?)
|
94
|
+
end
|
95
|
+
|
96
|
+
def started?
|
97
|
+
!!started_at
|
98
|
+
end
|
99
|
+
|
100
|
+
def running?
|
101
|
+
started? && !finished?
|
102
|
+
end
|
103
|
+
|
104
|
+
def failed?
|
105
|
+
jobs.any?(&:failed?)
|
106
|
+
end
|
107
|
+
|
108
|
+
def stopped?
|
109
|
+
stopped
|
110
|
+
end
|
111
|
+
|
112
|
+
def status
|
113
|
+
return :failed if failed?
|
114
|
+
return :running if running?
|
115
|
+
return :finished if finished?
|
116
|
+
return :stopped if stopped?
|
117
|
+
|
118
|
+
:running
|
119
|
+
end
|
120
|
+
|
121
|
+
def mark_as_persisted
|
122
|
+
@persisted = true
|
123
|
+
end
|
124
|
+
|
125
|
+
def mark_as_started
|
126
|
+
@stopped = false
|
127
|
+
end
|
128
|
+
|
129
|
+
|
130
|
+
private
|
131
|
+
|
132
|
+
def initial_jobs
|
133
|
+
jobs.select(&:no_dependencies?)
|
134
|
+
end
|
135
|
+
|
136
|
+
def setup
|
137
|
+
configure
|
138
|
+
resolve_dependencies
|
139
|
+
end
|
140
|
+
|
141
|
+
def resolve_dependencies
|
142
|
+
@dependencies.each do |dependency|
|
143
|
+
from = find_job(dependency[:from])
|
144
|
+
to = find_job(dependency[:to])
|
145
|
+
|
146
|
+
to.incomming << dependency[:from]
|
147
|
+
from.outgoing << dependency[:to]
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def build_dependencies_structure(node, options)
|
152
|
+
deps_after = [*options[:after]]
|
153
|
+
|
154
|
+
deps_after.each do |dep|
|
155
|
+
@dependencies << { from: dep.to_s, to: node.name.to_s }
|
156
|
+
end
|
157
|
+
|
158
|
+
deps_before = [*options[:before]]
|
159
|
+
|
160
|
+
deps_before.each do |dep|
|
161
|
+
@dependencies << { from: node.name.to_s, to: dep.to_s }
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
def client
|
166
|
+
@client ||= Dwf::Client.new
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
data/lib/dwf.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "bundler/setup"
|
3
|
+
|
4
|
+
require 'sidekiq'
|
5
|
+
require 'sidekiq-pro'
|
6
|
+
require 'json'
|
7
|
+
require 'byebug'
|
8
|
+
require 'redis'
|
9
|
+
|
10
|
+
require_relative 'dwf/utils'
|
11
|
+
require_relative 'dwf/workflow'
|
12
|
+
require_relative 'dwf/item'
|
13
|
+
require_relative 'dwf/client'
|
14
|
+
require_relative 'dwf/worker'
|
15
|
+
require_relative 'dwf/callback'
|
16
|
+
|
17
|
+
module Dwf
|
18
|
+
VERSION = '0.1.0'
|
19
|
+
end
|
20
|
+
|
metadata
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: dwf
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- dthtien
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2021-09-04 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: byebug
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 11.1.3
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 11.1.3
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: redis
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: 4.2.0
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: 4.2.0
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.2'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.2'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: sidekiq
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: 6.2.0
|
62
|
+
type: :runtime
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: 6.2.0
|
69
|
+
description: Workflow
|
70
|
+
email:
|
71
|
+
- tiendt2311@gmail.com
|
72
|
+
executables: []
|
73
|
+
extensions: []
|
74
|
+
extra_rdoc_files: []
|
75
|
+
files:
|
76
|
+
- ".gitignore"
|
77
|
+
- ".ruby-version"
|
78
|
+
- Gemfile
|
79
|
+
- LICENSE.txt
|
80
|
+
- README.md
|
81
|
+
- dwf.gemspec
|
82
|
+
- lib/dwf.rb
|
83
|
+
- lib/dwf/callback.rb
|
84
|
+
- lib/dwf/client.rb
|
85
|
+
- lib/dwf/item.rb
|
86
|
+
- lib/dwf/utils.rb
|
87
|
+
- lib/dwf/worker.rb
|
88
|
+
- lib/dwf/workflow.rb
|
89
|
+
homepage: https://github.com/dthtien/wf
|
90
|
+
licenses:
|
91
|
+
- MIT
|
92
|
+
metadata: {}
|
93
|
+
post_install_message:
|
94
|
+
rdoc_options: []
|
95
|
+
require_paths:
|
96
|
+
- lib
|
97
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: 2.4.0
|
102
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
103
|
+
requirements:
|
104
|
+
- - ">="
|
105
|
+
- !ruby/object:Gem::Version
|
106
|
+
version: '0'
|
107
|
+
requirements: []
|
108
|
+
rubygems_version: 3.2.3
|
109
|
+
signing_key:
|
110
|
+
specification_version: 4
|
111
|
+
summary: Gush cloned without ActiveJob but requried Sidekiq. This project is for researching
|
112
|
+
DSL purpose
|
113
|
+
test_files: []
|