dwf 0.1.9 → 0.1.10

Sign up to get free protection for your applications and to get access to all the features.
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