dwf 0.1.9 → 0.1.10

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: d37bac690df59157001462d6017a8a63d3956a280689de789d9a99163a476832
4
- data.tar.gz: 935d76e99ff5ca109f00be80c01950c20272969f556fc70d0e1ef5c026c024e4
3
+ metadata.gz: fba0bf3a5195787db6540ddfe2431a265b09b78859f333ed9295b4e4677d0a25
4
+ data.tar.gz: 66488a6107dec45933fc1631e713db3fb43a6e31dbd5d5a351a79a6bbb31f1f7
5
5
  SHA512:
6
- metadata.gz: c105d178cd44f12577ee9eeed5065768a23adc508da7d686e50c46d26e4eed9c160dc71b10942ab8041e38f6c732384742f40fa9d3076e0a924fbdfb1cd62845
7
- data.tar.gz: ad9c6f1041f092847364e91408887be311435be62e0502ab54f2b408c92fc598a879792eabb00c81b05d5c97fb37ea4a19136765d54b0d4efe9dbdb9ad2f64b5
6
+ metadata.gz: 88c01767c12ae11ff5f2aaeaf68b08a8c04a54bb909c51babd0f02cd915b1c8d790131c197034bbce46a8ab4d8e0dfa40a0f7afe4f1353bff65d952654438454
7
+ data.tar.gz: 799827548d718f4ae763c00c4519f636f448eb0aba40e6d5a60f83443cf2f479b3d8fbfd536744e11fc9092d22be3a18a7bb764b25cafcb27eccef3168ab0170
data/CHANGELOG.md CHANGED
@@ -1,5 +1,28 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
+ ## 0.1.10
4
+ ### Added
5
+ - Allow to use argument within workflow and update the defining callback way
6
+ ```
7
+ class TestWf < Dwf::Workflow
8
+ def configure(arguments)
9
+ run A
10
+ run B, after: A, params: argument
11
+ run C, after: A, params: argument
12
+ end
13
+ end
14
+
15
+ wf = TestWf.create(arguments)
16
+ wf.callback_type = Dwf::Workflow::SK_BATCH
17
+
18
+ ```
19
+ - Support `find` workflow and `reload` workflow
20
+ ```
21
+ wf = TestWf.create
22
+ Dwf::Workflow.find(wf.id)
23
+ wf.reload
24
+ ```
25
+
3
26
  ## 0.1.9
4
27
  ### Added
5
28
  ### Fixed
data/README.md CHANGED
@@ -41,7 +41,8 @@ end
41
41
 
42
42
  ### Execute flow
43
43
  ```ruby
44
- wf = TestWf.create(callback_type: Dwf::Workflow::SK_BATCH)
44
+ wf = TestWf.create
45
+ wf.callback_type = Dwf::Workflow::SK_BATCH
45
46
  wf.start!
46
47
  ```
47
48
 
@@ -125,8 +126,11 @@ end
125
126
  - [x] Add github workflow
126
127
  - [x] Redis configurable
127
128
  - [x] Pinelining
128
- - [ ] [WIP] Test
129
+ - [X] Test
130
+ - [ ] Consistent item name
129
131
  - [ ] Support [Resque](https://github.com/resque/resque)
132
+ - [ ] Key value store plugable
133
+ - [ ] research https://github.com/moneta-rb/moneta
130
134
 
131
135
  # References
132
136
  - https://github.com/chaps-io/gush
data/dwf.gemspec CHANGED
@@ -6,7 +6,7 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
6
 
7
7
  Gem::Specification.new do |spec|
8
8
  spec.name = "dwf"
9
- spec.version = '0.1.9'
9
+ spec.version = '0.1.10'
10
10
  spec.authors = ["dthtien"]
11
11
  spec.email = ["tiendt2311@gmail.com"]
12
12
 
data/lib/dwf/client.rb CHANGED
@@ -1,3 +1,5 @@
1
+ require_relative 'errors'
2
+
1
3
  module Dwf
2
4
  class Client
3
5
  attr_reader :config
@@ -20,6 +22,16 @@ module Dwf
20
22
  Dwf::Item.from_hash(Dwf::Utils.symbolize_keys(data))
21
23
  end
22
24
 
25
+ def find_workflow(id)
26
+ data = redis.get("dwf.workflows.#{id}")
27
+ raise WorkflowNotFound, "Workflow with given id doesn't exist" if data.nil?
28
+
29
+ hash = JSON.parse(data)
30
+ hash = Dwf::Utils.symbolize_keys(hash)
31
+ nodes = parse_nodes(id)
32
+ workflow_from_hash(hash, nodes)
33
+ end
34
+
23
35
  def persist_job(job)
24
36
  redis.hset("dwf.jobs.#{job.workflow_id}.#{job.klass}", job.id, job.as_json)
25
37
  end
@@ -99,6 +111,28 @@ module Dwf
99
111
  job
100
112
  end
101
113
 
114
+ def parse_nodes(id)
115
+ keys = redis.scan_each(match: "dwf.jobs.#{id}.*")
116
+
117
+ keys.map do |key|
118
+ redis.hvals(key).map do |json|
119
+ Dwf::Utils.symbolize_keys JSON.parse(json)
120
+ end
121
+ end.flatten
122
+ end
123
+
124
+ def workflow_from_hash(hash, nodes = [])
125
+ flow = Module.const_get(hash[:klass]).new(*hash[:arguments])
126
+ flow.jobs = []
127
+ flow.stopped = hash.fetch(:stopped, false)
128
+ flow.id = hash[:id]
129
+ flow.jobs = nodes.map do |node|
130
+ Dwf::Item.from_hash(node)
131
+ end
132
+
133
+ flow
134
+ end
135
+
102
136
  def redis
103
137
  @redis ||= Redis.new(config.redis_opts)
104
138
  end
data/lib/dwf/errors.rb ADDED
@@ -0,0 +1,3 @@
1
+ module Dwf
2
+ class WorkflowNotFound < StandardError; end
3
+ end
data/lib/dwf/workflow.rb CHANGED
@@ -10,8 +10,8 @@ module Dwf
10
10
  BUILD_IN = 'build-in',
11
11
  SK_BATCH = 'sk-batch'
12
12
  ].freeze
13
- attr_reader :dependencies, :jobs, :started_at, :finished_at, :persisted, :stopped,
14
- :callback_type
13
+ attr_accessor :jobs, :callback_type, :stopped, :id
14
+ attr_reader :dependencies, :started_at, :finished_at, :persisted, :arguments
15
15
 
16
16
  class << self
17
17
  def create(*args)
@@ -19,41 +19,58 @@ module Dwf
19
19
  flow.save
20
20
  flow
21
21
  end
22
+
23
+ def find(id)
24
+ Dwf::Client.new.find_workflow(id)
25
+ end
22
26
  end
23
27
 
24
- def initialize(options = {})
28
+ def initialize(*args)
25
29
  @dependencies = []
26
- @id = id
30
+ @id = build_id
27
31
  @jobs = []
28
32
  @persisted = false
29
33
  @stopped = false
30
- @callback_type = options[:callback_type] || BUILD_IN
34
+ @arguments = args
35
+ @callback_type = BUILD_IN
31
36
 
32
37
  setup
33
38
  end
34
39
 
40
+ def persist!
41
+ client.persist_workflow(self)
42
+ jobs.each(&:persist!)
43
+ mark_as_persisted
44
+ true
45
+ end
46
+
47
+ alias save persist!
48
+
35
49
  def start!
50
+ mark_as_started
51
+ persist!
36
52
  initial_jobs.each do |job|
37
53
  cb_build_in? ? job.persist_and_perform_async! : Dwf::Callback.new.start(job)
38
54
  end
39
55
  end
40
56
 
41
- def save
42
- client.persist_workflow(self)
43
- jobs.each(&:persist!)
44
- mark_as_persisted
45
- true
57
+ def reload
58
+ flow = self.class.find(id)
59
+ self.stopped = flow.stopped
60
+ self.jobs = flow.jobs
61
+
62
+ self
46
63
  end
47
64
 
48
65
  def cb_build_in?
49
66
  callback_type == BUILD_IN
50
67
  end
51
68
 
52
- def id
53
- @id ||= client.build_workflow_id
69
+ def build_id
70
+ client.build_workflow_id
54
71
  end
55
72
 
56
- def configure; end
73
+ def configure(*arguments); end
57
74
 
58
75
  def run(klass, options = {})
59
76
  node = klass.new(
@@ -140,7 +157,6 @@ module Dwf
140
157
  @stopped = false
141
158
  end
142
159
 
143
-
144
160
  private
145
161
 
146
162
  def initial_jobs
@@ -148,7 +164,7 @@ module Dwf
148
164
  end
149
165
 
150
166
  def setup
151
- configure
167
+ configure(*arguments)
152
168
  resolve_dependencies
153
169
  end
154
170
 
@@ -39,6 +39,29 @@ describe Dwf::Client, client: true do
39
39
  end
40
40
  end
41
41
 
42
+ describe '#find_workflow' do
43
+ before do
44
+ wf = Dwf::Workflow.new
45
+ wf.id = workflow_id
46
+ wf.save
47
+ j = Dwf::Item.new(id: id, workflow_id: workflow_id)
48
+ j.persist!
49
+ end
50
+
51
+ it do
52
+ wf = client.find_workflow(workflow_id)
53
+
54
+ expect(wf).not_to be_nil
55
+ expect(wf.jobs.first).to be_kind_of(Dwf::Item)
56
+ end
57
+
58
+ it do
59
+ expect do
60
+ client.find_workflow(SecureRandom.uuid)
61
+ end.to raise_error Dwf::WorkflowNotFound
62
+ end
63
+ end
64
+
42
65
  describe '#persist_job' do
43
66
  let!(:job) { Dwf::Item.new(workflow_id: workflow_id, id: id) }
44
67
 
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'mock_redis'
5
+ class AItem < Dwf::Item; end
6
+
7
+ class BItem < Dwf::Item; end
8
+
9
+ class CItem < Dwf::Item; end
10
+
11
+ describe Dwf::Workflow, workflow: true do
12
+ let(:workflow_id) { SecureRandom.uuid }
13
+ let(:item_id) { SecureRandom.uuid }
14
+ let(:client) do
15
+ double(
16
+ persist_workflow: nil,
17
+ persist_job: nil,
18
+ build_workflow_id: workflow_id,
19
+ build_job_id: item_id,
20
+ find_workflow: nil
21
+ )
22
+ end
23
+ before do
24
+ allow(Dwf::Client).to receive(:new).and_return client
25
+ end
26
+
27
+ describe '#create' do
28
+ it do
29
+ workflow = described_class.create
30
+ expect(client).to have_received(:persist_workflow)
31
+ .with(an_instance_of(described_class))
32
+ expect(workflow.id).to eq workflow_id
33
+ expect(workflow.persisted).to be_truthy
34
+ end
35
+ end
36
+
37
+ describe '#find' do
38
+ before { Dwf::Workflow.find(workflow_id) }
39
+
40
+ it { expect(client).to have_received(:find_workflow).with(workflow_id) }
41
+ end
42
+
43
+ describe '#persist!' do
44
+ let(:workflow) { described_class.new }
45
+ let(:job) do
46
+ Dwf::Item.new(
47
+ worflow_id: workflow_id,
48
+ id: item_id
49
+ )
50
+ end
51
+ before do
52
+ workflow.jobs << job
53
+ workflow.persist!
54
+ end
55
+
56
+ it do
57
+ expect(client).to have_received(:persist_workflow)
58
+ .with(an_instance_of(described_class))
59
+ expect(client).to have_received(:persist_job).with(job)
60
+ expect(workflow.id).to eq workflow_id
61
+ expect(workflow.persisted).to be_truthy
62
+ end
63
+ end
64
+
65
+ describe '#start' do
66
+ let(:workflow) { described_class.new }
67
+ let(:job) do
68
+ Dwf::Item.new(
69
+ worflow_id: workflow_id,
70
+ id: item_id
71
+ )
72
+ end
73
+ before do
74
+ workflow.jobs << job
75
+ workflow.persist!
76
+ end
77
+
78
+ it do
79
+ expect(client).to have_received(:persist_workflow)
80
+ .with(an_instance_of(described_class))
81
+ expect(client).to have_received(:persist_job).with(job)
82
+ expect(workflow.id).to eq workflow_id
83
+ expect(workflow.persisted).to be_truthy
84
+ expect(workflow.stopped).to be_falsy
85
+ end
86
+ end
87
+
88
+ describe '#run' do
89
+ let!(:workflow) { described_class.new }
90
+
91
+ before do
92
+ workflow.run AItem, after: BItem, before: CItem
93
+ end
94
+
95
+ it do
96
+ expect(workflow.jobs).not_to be_empty
97
+ expected = [
98
+ {
99
+ from: BItem.to_s,
100
+ to: "AItem|#{item_id}"
101
+ },
102
+ {
103
+ from: "AItem|#{item_id}",
104
+ to: CItem.to_s
105
+ }
106
+ ]
107
+ expect(workflow.dependencies).to match_array expected
108
+ end
109
+ end
110
+
111
+ describe '#find_job' do
112
+ let!(:workflow) { described_class.new }
113
+ before do
114
+ workflow.jobs = [
115
+ AItem.new,
116
+ BItem.new(id: item_id),
117
+ CItem.new
118
+ ]
119
+ end
120
+
121
+ it 'searches by klass' do
122
+ job = workflow.find_job('AItem')
123
+ expect(job).to be_kind_of AItem
124
+ end
125
+
126
+ it 'searches by name' do
127
+ job = workflow.find_job("BItem|#{item_id}")
128
+ expect(job).to be_kind_of BItem
129
+ end
130
+ end
131
+
132
+ describe '#setup' do
133
+ let!(:workflow) { described_class.new }
134
+ before do
135
+ workflow.run AItem
136
+ workflow.run BItem, after: AItem
137
+ workflow.run CItem, after: BItem
138
+
139
+ workflow.send(:setup)
140
+ end
141
+
142
+ it do
143
+ job_a = workflow.find_job('AItem')
144
+
145
+ expect(job_a.incoming).to be_empty
146
+ expect(job_a.outgoing).to eq ["BItem|#{item_id}"]
147
+
148
+ job_b = workflow.find_job('BItem')
149
+
150
+ expect(job_b.incoming).to eq ['AItem']
151
+ expect(job_b.outgoing).to eq ["CItem|#{item_id}"]
152
+
153
+ job_c = workflow.find_job('CItem')
154
+
155
+ expect(job_c.incoming).to eq ['BItem']
156
+ expect(job_c.outgoing).to be_empty
157
+ end
158
+ end
159
+
160
+ describe '#callback_type' do
161
+ let!(:workflow) { described_class.new }
162
+
163
+ it {
164
+ expect(workflow.callback_type).to eq described_class::BUILD_IN
165
+ workflow.callback_type = described_class::SK_BATCH
166
+ expect(workflow.callback_type).to eq described_class::SK_BATCH
167
+ }
168
+ end
169
+
170
+ describe '#reload' do
171
+ let!(:workflow) do
172
+ flow = described_class.new
173
+ flow.id = workflow_id
174
+ flow
175
+ end
176
+
177
+ before do
178
+ allow(client).to receive(:find_workflow).and_return workflow
179
+ workflow.reload
180
+ end
181
+
182
+ it { expect(client).to have_received(:find_workflow).with(workflow_id) }
183
+ end
184
+ 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.9
4
+ version: 0.1.10
5
5
  platform: ruby
6
6
  authors:
7
7
  - dthtien
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-09-10 00:00:00.000000000 Z
11
+ date: 2021-09-12 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -101,6 +101,7 @@ files:
101
101
  - lib/dwf/callback.rb
102
102
  - lib/dwf/client.rb
103
103
  - lib/dwf/configuration.rb
104
+ - lib/dwf/errors.rb
104
105
  - lib/dwf/item.rb
105
106
  - lib/dwf/utils.rb
106
107
  - lib/dwf/version.rb
@@ -111,6 +112,7 @@ files:
111
112
  - spec/dwf/item_spec.rb
112
113
  - spec/dwf/utils_spec.rb
113
114
  - spec/dwf/worker_spec.rb
115
+ - spec/dwf/workflow_spec.rb
114
116
  - spec/spec_helper.rb
115
117
  homepage: https://github.com/dthtien/wf
116
118
  licenses:
@@ -142,4 +144,5 @@ test_files:
142
144
  - spec/dwf/item_spec.rb
143
145
  - spec/dwf/utils_spec.rb
144
146
  - spec/dwf/worker_spec.rb
147
+ - spec/dwf/workflow_spec.rb
145
148
  - spec/spec_helper.rb