dwf 0.1.3 → 0.1.4

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: 0057d6d96f647afa204d1ece11e64444df31b3db21c6ceda3ac92ac73c134105
4
- data.tar.gz: f7f1aff90493a9396a7bf13f9e7f6a3c348e32022e73e907ef8571b89c70efd6
3
+ metadata.gz: 3cdc42799fb3b0f4a00ea31256b5f134c1b804ebd0d7b1b0f78d1804814a3633
4
+ data.tar.gz: 9cf8df64c36c5fea2480c285d7d3a07d78f256c9e67d41b6835a462dc9bf0bc1
5
5
  SHA512:
6
- metadata.gz: 9207d683e57e95e8fd3e555c2a589fb4be793a8a4cafc479e2446fdd1ab3e180b72154b4c4b8f93aca92bd06159ec8eb3df448ffce0b742bd647ec723088ef4d
7
- data.tar.gz: 41fdfb04643bdba4e7afda031308c19a347762aebc281fd42ac7f4be6be5d932a8a2fb610d38276338c07ac0b2835e3e12585796b7d39266e3a97976a39a4e7c
6
+ metadata.gz: 7e959a506185de817405e9bfcd5fcc186e09c1654a03b998117859f9d50988234efde5641a7399813f5c32b2c4a996f29f4085145ff1fd2a92f18c845b1f50b1
7
+ data.tar.gz: 1e226df92dde539afeb3125457153fd9f56db03b9e983cd5a24ccd6ef0cd98fa9043a35c4838b360afe4c6ac116a761e85a5ea7769035aa81d0e3c0f6858f78a
@@ -0,0 +1,25 @@
1
+ name: dwf
2
+
3
+ on:
4
+ push:
5
+ branches:
6
+ - '**'
7
+ pull_request:
8
+ branches:
9
+ - '**'
10
+
11
+ jobs:
12
+ test:
13
+
14
+ runs-on: ubuntu-latest
15
+
16
+ steps:
17
+ - uses: actions/checkout@v2
18
+ - name: Set up Ruby
19
+ uses: ruby/setup-ruby@477b21f02be01bcb8030d50f37cfec92bfa615b6
20
+ with:
21
+ ruby-version: 3.0.0
22
+ - name: Install dependencies
23
+ run: bundle install
24
+ - name: Run tests
25
+ run: bundle exec rspec --require spec_helper
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --require spec_helper
2
+ --color
3
+ --format documentation
data/Gemfile CHANGED
@@ -2,7 +2,7 @@ source "https://rubygems.org"
2
2
 
3
3
  gemspec
4
4
 
5
- source "https://gems.contribsys.com/" do
6
- gem 'sidekiq-pro'
7
- end
5
+ # source "https://gems.contribsys.com/" do
6
+ # gem 'sidekiq-pro'
7
+ # end
8
8
 
data/README.md CHANGED
@@ -2,11 +2,12 @@
2
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
3
 
4
4
  # Installation
5
+ ## 1. Add `dwf` to Gemfile
5
6
  ```ruby
6
- gem 'dwf', '~> 0.1.2'
7
+ gem 'dwf', '~> 0.1.3'
7
8
  ```
8
- # Execute flow
9
- ## Declare jobs
9
+ ## 2. Execute flow
10
+ ### Declare jobs
10
11
 
11
12
  ```ruby
12
13
  require 'dwf'
@@ -21,7 +22,7 @@ class A < Dwf::Item
21
22
  end
22
23
  ```
23
24
 
24
- ## Declare flow
25
+ ### Declare flow
25
26
  ```ruby
26
27
  require 'dwf'
27
28
 
@@ -35,11 +36,14 @@ class TestWf < Dwf::Workflow
35
36
  run F, params: 'F say hello'
36
37
  end
37
38
  end
39
+ ```
38
40
 
39
- wf = TestWf.create
40
- wf.start!
41
+ #### Note
42
+ `dwf` supports 2 type of callback `Dwf::Workflow::BUILD_IN` and `Dwf::Workflow::SK_BATCH`
43
+ - `Dwf::Workflow::BUILD_IN` is a build-in callback
44
+ - `Dwf::Workflow::SK_BATCH` is [sidekiq batch](https://github.com/mperham/sidekiq/wiki/Batches) callback which required [`sidekiq-pro`](https://sidekiq.org/products/pro.html)
41
45
 
42
- ```
46
+ By default `dwf` will use `Dwf::Workflow::BUILD_IN` callback.
43
47
 
44
48
  ### Execute flow
45
49
  ```ruby
@@ -69,7 +73,7 @@ D Finished
69
73
  # Todo
70
74
  - [x] Make it work
71
75
  - [x] Support pass params
72
- - [ ] Support with build-in callback
76
+ - [x] Support with build-in callback
73
77
  - [ ] Test
74
78
  - [ ] Add github workflow
75
79
  - [ ] Transfer output through each node
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.3'
9
+ spec.version = '0.1.4'
10
10
  spec.authors = ["dthtien"]
11
11
  spec.email = ["tiendt2311@gmail.com"]
12
12
 
data/lib/dwf/callback.rb CHANGED
@@ -1,4 +1,3 @@
1
- require 'sidekiq-pro'
2
1
  require_relative 'client'
3
2
 
4
3
  module Dwf
data/lib/dwf/item.rb CHANGED
@@ -1,19 +1,23 @@
1
+ # frozen_string_literal: true
1
2
  require_relative 'client'
2
3
 
3
4
  module Dwf
4
5
  class Item
6
+ DEFAULT_QUEUE = 'default'
7
+
5
8
  attr_reader :workflow_id, :id, :params, :queue, :klass, :started_at,
6
9
  :enqueued_at, :finished_at, :failed_at, :callback_type
7
- attr_accessor :incomming, :outgoing
10
+ attr_accessor :incoming, :outgoing
8
11
 
9
12
  def initialize(options = {})
10
13
  @workflow_id = options[:workflow_id]
11
14
  @id = options[:id]
12
15
  @params = options[:params]
13
- @queue = options[:queue] || 'default'
14
- @incomming = options[:incoming] || []
16
+ @queue = options[:queue] || DEFAULT_QUEUE
17
+ @incoming = options[:incoming] || []
15
18
  @outgoing = options[:outgoing] || []
16
19
  @klass = options[:klass] || self.class
20
+ @failed_at = options[:failed_at]
17
21
  @finished_at = options[:finished_at]
18
22
  @enqueued_at = options[:enqueued_at]
19
23
  @started_at = options[:started_at]
@@ -45,11 +49,11 @@ module Dwf
45
49
  end
46
50
 
47
51
  def no_dependencies?
48
- incomming.empty?
52
+ incoming.empty?
49
53
  end
50
54
 
51
55
  def parents_succeeded?
52
- incomming.all? do |name|
56
+ incoming.all? do |name|
53
57
  client.find_job(workflow_id, name).succeeded?
54
58
  end
55
59
  end
@@ -130,7 +134,7 @@ module Dwf
130
134
  id: id,
131
135
  klass: klass.to_s,
132
136
  queue: queue,
133
- incoming: incomming,
137
+ incoming: incoming,
134
138
  outgoing: outgoing,
135
139
  finished_at: finished_at,
136
140
  enqueued_at: enqueued_at,
data/lib/dwf/workflow.rb CHANGED
@@ -157,7 +157,7 @@ module Dwf
157
157
  from = find_job(dependency[:from])
158
158
  to = find_job(dependency[:to])
159
159
 
160
- to.incomming << dependency[:from]
160
+ to.incoming << dependency[:from]
161
161
  from.outgoing << dependency[:to]
162
162
  end
163
163
  end
data/lib/dwf.rb CHANGED
@@ -4,6 +4,7 @@ require "bundler/setup"
4
4
  require 'sidekiq'
5
5
  require 'json'
6
6
  require 'redis'
7
+ # require 'sidekiq-pro'
7
8
 
8
9
  require_relative 'dwf/utils'
9
10
  require_relative 'dwf/workflow'
@@ -13,6 +14,6 @@ require_relative 'dwf/worker'
13
14
  require_relative 'dwf/callback'
14
15
 
15
16
  module Dwf
16
- VERSION = '0.1.0'
17
+ VERSION = '0.1.3'
17
18
  end
18
19
 
@@ -0,0 +1,184 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Dwf::Item, item: true do
6
+ let!(:id) { SecureRandom.uuid }
7
+ let!(:workflow_id) { SecureRandom.uuid }
8
+ let(:incoming) { [] }
9
+ let(:outgoing) { [] }
10
+ let(:started_at) { nil }
11
+ let(:finished_at) { nil }
12
+ let(:options) do
13
+ {
14
+ workflow_id: workflow_id,
15
+ id: id,
16
+ params: {},
17
+ incoming: incoming,
18
+ outgoing: outgoing,
19
+ queue: Dwf::Item::DEFAULT_QUEUE,
20
+ klass: 'Dwf::Item',
21
+ started_at: started_at,
22
+ finished_at: finished_at,
23
+ callback_type: Dwf::Workflow::BUILD_IN
24
+ }
25
+ end
26
+ let!(:item) { described_class.new(options) }
27
+
28
+ describe 'self.from_hash' do
29
+ let!(:item) { described_class.from_hash(options) }
30
+ it { expect(item.to_hash.compact).to eq options.compact }
31
+ end
32
+
33
+ describe '#persist_and_perform_async!' do
34
+ let(:worker_double) { double(perform_async: nil) }
35
+ let(:client_double) { double(persist_job: nil) }
36
+
37
+ before do
38
+ allow(Dwf::Client).to receive(:new).and_return client_double
39
+ allow(Dwf::Worker).to receive(:set).and_return worker_double
40
+ item.persist_and_perform_async!
41
+ end
42
+
43
+ it do
44
+ expect(worker_double)
45
+ .to have_received(:perform_async)
46
+ .with(item.workflow_id, item.name)
47
+ expect(client_double).to have_received(:persist_job).with(item)
48
+ expect(item.enqueued_at).not_to be_nil
49
+ end
50
+ end
51
+
52
+ describe '#cb_build_in?' do
53
+ it { expect(item.cb_build_in?).to be_truthy }
54
+ end
55
+
56
+ describe '#perform_async' do
57
+ let(:worker_double) { double(perform_async: nil) }
58
+ before do
59
+ allow(Dwf::Worker).to receive(:set).and_return worker_double
60
+ item.perform_async
61
+ end
62
+
63
+ it do
64
+ expect(worker_double)
65
+ .to have_received(:perform_async)
66
+ .with(item.workflow_id, item.name)
67
+ end
68
+ end
69
+
70
+ describe '#name' do
71
+ it { expect(item.name).to eq "#{described_class}|#{id}" }
72
+ end
73
+
74
+ describe '#no_dependencies?' do
75
+ it { expect(item.no_dependencies?).to be_truthy }
76
+ end
77
+
78
+ describe '#parents_succeeded?' do
79
+ let(:incoming) { ["A|#{SecureRandom.uuid}"] }
80
+ let(:client_double) { double(find_job: nil) }
81
+ let(:a_item) do
82
+ described_class.new(
83
+ workflow_id: SecureRandom.uuid,
84
+ id: SecureRandom.uuid,
85
+ finished_at: finished_at
86
+ )
87
+ end
88
+
89
+ before do
90
+ allow(Dwf::Client).to receive(:new).and_return client_double
91
+ allow(client_double)
92
+ .to receive(:find_job).and_return a_item
93
+ end
94
+
95
+ context 'parent jobs already finished' do
96
+ let(:finished_at) { Time.now.to_i }
97
+
98
+ it do
99
+ expect(item.parents_succeeded?).to be_truthy
100
+ expect(client_double)
101
+ .to have_received(:find_job)
102
+ .with(workflow_id, incoming.first)
103
+ end
104
+ end
105
+
106
+ context 'parent jobs havent finished yet' do
107
+ let(:finished_at) { nil }
108
+
109
+ it do
110
+ expect(item.parents_succeeded?).to be_falsy
111
+ expect(client_double)
112
+ .to have_received(:find_job)
113
+ .with(workflow_id, incoming.first)
114
+ end
115
+ end
116
+ end
117
+
118
+ describe '#enqueue!' do
119
+ before { item.enqueue! }
120
+
121
+ it { expect(item.enqueued_at).not_to be_nil }
122
+ end
123
+
124
+ describe '#mark_as_started' do
125
+ let(:client_double) { double(persist_job: nil) }
126
+ before do
127
+ allow(Dwf::Client).to receive(:new).and_return client_double
128
+ item.mark_as_started
129
+ end
130
+
131
+ it do
132
+ expect(client_double).to have_received(:persist_job).with item
133
+ expect(item.started_at).not_to be_nil
134
+ end
135
+ end
136
+
137
+ describe '#mark_as_finished' do
138
+ let(:client_double) { double(persist_job: nil) }
139
+ before do
140
+ allow(Dwf::Client).to receive(:new).and_return client_double
141
+ item.mark_as_finished
142
+ end
143
+
144
+ it do
145
+ expect(client_double).to have_received(:persist_job).with item
146
+ expect(item.finished_at).not_to be_nil
147
+ end
148
+ end
149
+
150
+ describe '#enqueue_outgoing_jobs' do
151
+ let(:outgoing) { ["A|#{SecureRandom.uuid}"] }
152
+ let(:client_double) do
153
+ double(
154
+ find_job: nil,
155
+ check_or_lock: nil,
156
+ release_lock: nil
157
+ )
158
+ end
159
+ let(:a_item) do
160
+ described_class.new(
161
+ workflow_id: SecureRandom.uuid,
162
+ id: SecureRandom.uuid,
163
+ started_at: started_at
164
+ )
165
+ end
166
+ before do
167
+ allow(Dwf::Client).to receive(:new).and_return client_double
168
+ allow(a_item).to receive(:persist_and_perform_async!)
169
+ allow(client_double)
170
+ .to receive(:find_job).and_return a_item
171
+ item.enqueue_outgoing_jobs
172
+ end
173
+
174
+ context 'outgoing jobs ready to start' do
175
+ let(:started_at) { nil }
176
+ it { expect(a_item).to have_received(:persist_and_perform_async!) }
177
+ end
178
+
179
+ context 'outgoing jobs havent ready to start' do
180
+ let(:started_at) { Time.now.to_i }
181
+ it { expect(a_item).not_to have_received(:persist_and_perform_async!) }
182
+ end
183
+ end
184
+ end
@@ -0,0 +1,23 @@
1
+ require 'spec_helper'
2
+
3
+ describe Dwf::Utils, utils: true do
4
+ describe '#symbolize_keys' do
5
+ let(:expected) do
6
+ {
7
+ incoming: ['S'],
8
+ outgoing: %w[A B],
9
+ klass: 'H'
10
+ }
11
+ end
12
+
13
+ let(:hash) do
14
+ {
15
+ 'incoming' => ['S'],
16
+ 'outgoing' => %w[A B],
17
+ 'klass' => 'H'
18
+ }
19
+ end
20
+
21
+ it { expect(described_class.symbolize_keys(hash)).to eq expected }
22
+ end
23
+ end
@@ -0,0 +1,101 @@
1
+ require 'dwf'
2
+ # This file was generated by the `rspec --init` command. Conventionally, all
3
+ # specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
4
+ # The generated `.rspec` file contains `--require spec_helper` which will cause
5
+ # this file to always be loaded, without a need to explicitly require it in any
6
+ # files.
7
+ #
8
+ # Given that it is always loaded, you are encouraged to keep this file as
9
+ # light-weight as possible. Requiring heavyweight dependencies from this file
10
+ # will add to the boot time of your test suite on EVERY test run, even for an
11
+ # individual file that may not need all of that loaded. Instead, consider making
12
+ # a separate helper file that requires the additional dependencies and performs
13
+ # the additional setup, and require it from the spec files that actually need
14
+ # it.
15
+ #
16
+ # See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
17
+ RSpec.configure do |config|
18
+ # rspec-expectations config goes here. You can use an alternate
19
+ # assertion/expectation library such as wrong or the stdlib/minitest
20
+ # assertions if you prefer.
21
+ config.expect_with :rspec do |expectations|
22
+ # This option will default to `true` in RSpec 4. It makes the `description`
23
+ # and `failure_message` of custom matchers include text for helper methods
24
+ # defined using `chain`, e.g.:
25
+ # be_bigger_than(2).and_smaller_than(4).description
26
+ # # => "be bigger than 2 and smaller than 4"
27
+ # ...rather than:
28
+ # # => "be bigger than 2"
29
+ expectations.include_chain_clauses_in_custom_matcher_descriptions = true
30
+ end
31
+
32
+ # rspec-mocks config goes here. You can use an alternate test double
33
+ # library (such as bogus or mocha) by changing the `mock_with` option here.
34
+ config.mock_with :rspec do |mocks|
35
+ # Prevents you from mocking or stubbing a method that does not exist on
36
+ # a real object. This is generally recommended, and will default to
37
+ # `true` in RSpec 4.
38
+ mocks.verify_partial_doubles = true
39
+ end
40
+
41
+ # This option will default to `:apply_to_host_groups` in RSpec 4 (and will
42
+ # have no way to turn it off -- the option exists only for backwards
43
+ # compatibility in RSpec 3). It causes shared context metadata to be
44
+ # inherited by the metadata hash of host groups and examples, rather than
45
+ # triggering implicit auto-inclusion in groups with matching metadata.
46
+ config.shared_context_metadata_behavior = :apply_to_host_groups
47
+
48
+ # The settings below are suggested to provide a good initial experience
49
+ # with RSpec, but feel free to customize to your heart's content.
50
+ =begin
51
+ # This allows you to limit a spec run to individual examples or groups
52
+ # you care about by tagging them with `:focus` metadata. When nothing
53
+ # is tagged with `:focus`, all examples get run. RSpec also provides
54
+ # aliases for `it`, `describe`, and `context` that include `:focus`
55
+ # metadata: `fit`, `fdescribe` and `fcontext`, respectively.
56
+ config.filter_run_when_matching :focus
57
+
58
+ # Allows RSpec to persist some state between runs in order to support
59
+ # the `--only-failures` and `--next-failure` CLI options. We recommend
60
+ # you configure your source control system to ignore this file.
61
+ config.example_status_persistence_file_path = "spec/examples.txt"
62
+
63
+ # Limits the available syntax to the non-monkey patched syntax that is
64
+ # recommended. For more details, see:
65
+ # - http://rspec.info/blog/2012/06/rspecs-new-expectation-syntax/
66
+ # - http://www.teaisaweso.me/blog/2013/05/27/rspecs-new-message-expectation-syntax/
67
+ # - http://rspec.info/blog/2014/05/notable-changes-in-rspec-3/#zero-monkey-patching-mode
68
+ config.disable_monkey_patching!
69
+
70
+ # This setting enables warnings. It's recommended, but in some cases may
71
+ # be too noisy due to issues in dependencies.
72
+ config.warnings = true
73
+
74
+ # Many RSpec users commonly either run the entire suite or an individual
75
+ # file, and it's useful to allow more verbose output when running an
76
+ # individual spec file.
77
+ if config.files_to_run.one?
78
+ # Use the documentation formatter for detailed output,
79
+ # unless a formatter has already been configured
80
+ # (e.g. via a command-line flag).
81
+ config.default_formatter = "doc"
82
+ end
83
+
84
+ # Print the 10 slowest examples and example groups at the
85
+ # end of the spec run, to help surface which specs are running
86
+ # particularly slow.
87
+ config.profile_examples = 10
88
+
89
+ # Run specs in random order to surface order dependencies. If you find an
90
+ # order dependency and want to debug it, you can fix the order by providing
91
+ # the seed, which is printed after each run.
92
+ # --seed 1234
93
+ config.order = :random
94
+
95
+ # Seed global randomization in this process using the `--seed` CLI option.
96
+ # Setting this allows you to use `--seed` to deterministically reproduce
97
+ # test failures related to randomization by passing the same `--seed` value
98
+ # as the one that triggered the failure.
99
+ Kernel.srand config.seed
100
+ =end
101
+ 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.3
4
+ version: 0.1.4
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-04 00:00:00.000000000 Z
11
+ date: 2021-09-05 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: byebug
@@ -73,7 +73,9 @@ executables: []
73
73
  extensions: []
74
74
  extra_rdoc_files: []
75
75
  files:
76
+ - ".github/workflows/test.yaml"
76
77
  - ".gitignore"
78
+ - ".rspec"
77
79
  - ".ruby-version"
78
80
  - Gemfile
79
81
  - LICENSE.txt
@@ -86,6 +88,9 @@ files:
86
88
  - lib/dwf/utils.rb
87
89
  - lib/dwf/worker.rb
88
90
  - lib/dwf/workflow.rb
91
+ - spec/dwf/item_spec.rb
92
+ - spec/dwf/utils_spec.rb
93
+ - spec/spec_helper.rb
89
94
  homepage: https://github.com/dthtien/wf
90
95
  licenses:
91
96
  - MIT
@@ -110,4 +115,7 @@ signing_key:
110
115
  specification_version: 4
111
116
  summary: Gush cloned without ActiveJob but requried Sidekiq. This project is for researching
112
117
  DSL purpose
113
- test_files: []
118
+ test_files:
119
+ - spec/dwf/item_spec.rb
120
+ - spec/dwf/utils_spec.rb
121
+ - spec/spec_helper.rb