dwf 0.1.6 → 0.1.7

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: a08560cdfefa1c9f8e1f42416599e94550de0f0e1492bb5b05424e2bf94a482f
4
- data.tar.gz: 84a83b6849b64e7fe5da74f5734e2d8faa96df25eef63a5d0de78229fcc733ba
3
+ metadata.gz: fb0f6f6f30b7ed1ba19120a4a1f77e450940e45433153de51f47df9f108d0fae
4
+ data.tar.gz: e0e86fdd169b7cbcdc811cf62f87b3043fbbd708bdf0f41fb006b392e4ab784b
5
5
  SHA512:
6
- metadata.gz: 6eb847d86872dfa70c1a602a3ae8ef0e0ca166cfa22d0a5e3706454ef0144ac434b48489a916d811e9dc66ebb9ef4979b00b63dee8da4d08c44af6d1bd714dad
7
- data.tar.gz: cda011bc87919531f5de78721c3640c2460119cb4dd5668bd4ebb8093e19d46e848d27cfc2112c10021bd41e52e2365ced092f779a25a1509086fdf7095221a9
6
+ metadata.gz: 4a3770d4d7f63b7ede02d59e1ce43cb2634b39cbd9e037c920e4f816acb7b393de0f9030fda735e8ea0873f3679da120ff405f725e87c60c1b9eb6a7fbf355e3
7
+ data.tar.gz: 469e25cdf11441c59c80ff47197dcabcf40e0b086ab06babb6b39a0597483517c479ee9ea65767819b69afebf83db6dcdb5926a9839a2e40d02c03cf39a6eb57
@@ -8,10 +8,6 @@ on:
8
8
  branches: [ master ]
9
9
  paths:
10
10
  - 'dwf.gemspec'
11
- pull_request:
12
- branches: [ master ]
13
- paths:
14
- - 'dwf.gemspec'
15
11
 
16
12
  jobs:
17
13
  build:
@@ -3,7 +3,7 @@ name: Test
3
3
  on:
4
4
  push:
5
5
  branches:
6
- - '**'
6
+ - 'master'
7
7
  pull_request:
8
8
  branches:
9
9
  - '**'
data/CHANGELOG.md CHANGED
@@ -1,5 +1,16 @@
1
1
  # Changelog
2
2
  All notable changes to this project will be documented in this file.
3
+ ## 0.1.7
4
+ ### Added
5
+ - Allow to config redis and queue
6
+
7
+ ```ruby
8
+ Dwf.config do |config|
9
+ config.opts = { url 'redis://127.0.0.1:6379' }
10
+ config.namespace = 'dwf'
11
+ end
12
+ ```
13
+
3
14
  ## 0.1.6
4
15
  ### Added
5
16
  - Sidekiq batch callback: separate batches
data/README.md CHANGED
@@ -4,7 +4,7 @@
4
4
  # Installation
5
5
  ## 1. Add `dwf` to Gemfile
6
6
  ```ruby
7
- gem 'dwf', '~> 0.1.5'
7
+ gem 'dwf', '~> 0.1.6'
8
8
  ```
9
9
  ## 2. Execute flow
10
10
  ### Declare jobs
@@ -38,12 +38,6 @@ class TestWf < Dwf::Workflow
38
38
  end
39
39
  ```
40
40
 
41
- #### Note
42
- `dwf` supports 2 callback types `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)
45
-
46
- By default `dwf` will use `Dwf::Workflow::BUILD_IN` callback.
47
41
 
48
42
  ### Execute flow
49
43
  ```ruby
@@ -51,6 +45,13 @@ wf = TestWf.create(callback_type: Dwf::Workflow::SK_BATCH)
51
45
  wf.start!
52
46
  ```
53
47
 
48
+ #### Note
49
+ `dwf` supports 2 callback types `Dwf::Workflow::BUILD_IN` and `Dwf::Workflow::SK_BATCH`
50
+ - `Dwf::Workflow::BUILD_IN` is a build-in callback
51
+ - `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)
52
+
53
+ By default `dwf` will use `Dwf::Workflow::BUILD_IN` callback.
54
+
54
55
  ### Output
55
56
  ```
56
57
  A Working
@@ -70,11 +71,25 @@ D say hello
70
71
  D Finished
71
72
  ```
72
73
 
74
+ # Config redis and default queue
75
+ ```ruby
76
+ Dwf.config do |config|
77
+ SENTINELS = [
78
+ { host: "127.0.0.1", port: 26380 },
79
+ { host: "127.0.0.1", port: 26381 }
80
+ ]
81
+ config.opts = { host: 'mymaster', sentinels: SENTINELS, role: :master }
82
+ config.namespace = 'dwf'
83
+ end
84
+ ```
85
+
86
+
73
87
  # Todo
74
88
  - [x] Make it work
75
89
  - [x] Support pass params
76
90
  - [x] Support with build-in callback
77
91
  - [x] Add github workflow
92
+ - [x] Redis configurable
78
93
  - [ ] [WIP] Test
79
94
  - [ ] Transfer output through each node
80
95
  - [ ] Support [Resque](https://github.com/resque/resque)
data/dwf.gemspec CHANGED
@@ -3,10 +3,11 @@
3
3
 
4
4
  lib = File.expand_path('../lib', __FILE__)
5
5
  $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
6
+ require_relative 'lib/dwf/version'
6
7
 
7
8
  Gem::Specification.new do |spec|
8
9
  spec.name = "dwf"
9
- spec.version = '0.1.6'
10
+ spec.version = Dwf::VERSION
10
11
  spec.authors = ["dthtien"]
11
12
  spec.email = ["tiendt2311@gmail.com"]
12
13
 
@@ -27,5 +28,6 @@ Gem::Specification.new do |spec|
27
28
  spec.add_development_dependency 'byebug', '~> 11.1.3'
28
29
  spec.add_dependency 'redis', '~> 4.2.0'
29
30
  spec.add_development_dependency 'rspec', '~> 3.2'
31
+ spec.add_development_dependency 'mock_redis', '~> 0.27.2'
30
32
  spec.add_dependency 'sidekiq', '~> 6.2.0'
31
33
  end
data/lib/dwf/callback.rb CHANGED
@@ -1,7 +1,10 @@
1
+ # frozen_string_literal: true
1
2
  require_relative 'client'
2
3
 
3
4
  module Dwf
4
5
  class Callback
6
+ DEFAULT_KEY = 'default_key'
7
+
5
8
  def process_next_step(status, options)
6
9
  previous_job_names = options['names']
7
10
  workflow_id = options['workflow_id']
@@ -12,7 +15,7 @@ module Dwf
12
15
  return if processing_job_names.empty?
13
16
 
14
17
  overall = Sidekiq::Batch.new(status.parent_bid)
15
- overall.jobs { setup_batch(processing_job_names, workflow_id) }
18
+ overall.jobs { setup_batches(processing_job_names, workflow_id) }
16
19
  end
17
20
 
18
21
  def start(job)
@@ -21,38 +24,36 @@ module Dwf
21
24
 
22
25
  private
23
26
 
24
- def setup_batch(processing_job_names, workflow_id)
27
+ def setup_batches(processing_job_names, workflow_id)
25
28
  jobs = fetch_jobs(processing_job_names, workflow_id)
26
29
  jobs_classification = classify_jobs jobs
27
30
 
28
- jobs_classification.values.each do |batch_jobs|
29
- batch = Sidekiq::Batch.new
30
- batch.on(
31
- :success,
32
- 'Dwf::Callback#process_next_step',
33
- names: batch_jobs.map(&:klass),
34
- workflow_id: workflow_id
35
- )
36
-
37
- batch.jobs do
38
- batch_jobs.each do |job|
39
- job.persist_and_perform_async! if job.ready_to_start?
40
- end
31
+ jobs_classification.each do |key, batch_jobs|
32
+ with_lock workflow_id, key do
33
+ setup_batch(batch_jobs, workflow_id)
41
34
  end
42
35
  end
43
36
  end
44
37
 
38
+ def setup_batch(jobs, workflow_id)
39
+ batch = Sidekiq::Batch.new
40
+ batch.on(
41
+ :success,
42
+ 'Dwf::Callback#process_next_step',
43
+ names: jobs.map(&:klass),
44
+ workflow_id: workflow_id
45
+ )
46
+ batch.jobs do
47
+ jobs.each { |job| job.persist_and_perform_async! if job.ready_to_start? }
48
+ end
49
+ end
50
+
45
51
  def classify_jobs(jobs)
46
52
  hash = {}
47
53
  jobs.each do |job|
48
54
  outgoing_jobs = job.outgoing
49
- key = outgoing_jobs.empty? ? 'default_key' : outgoing_jobs.join
50
-
51
- if hash[key].nil?
52
- hash[key] = [job]
53
- else
54
- hash[key] = hash[key].push(job)
55
- end
55
+ key = outgoing_jobs.empty? ? DEFAULT_KEY : outgoing_jobs.join
56
+ hash[key] = hash[key].nil? ? [job] : hash[key].push(job)
56
57
  end
57
58
 
58
59
  hash
@@ -64,13 +65,6 @@ module Dwf
64
65
  end.compact
65
66
  end
66
67
 
67
- def perform_job(job_name, workflow_id)
68
- with_lock workflow_id, job_name do
69
- job = client.find_job(workflow_id, job_name)
70
- job.persist_and_perform_async! if job.ready_to_start?
71
- end
72
- end
73
-
74
68
  def with_lock(workflow_id, job_name)
75
69
  client.check_or_lock(workflow_id, job_name)
76
70
  yield
data/lib/dwf/client.rb CHANGED
@@ -1,5 +1,11 @@
1
1
  module Dwf
2
2
  class Client
3
+ attr_reader :config
4
+
5
+ def initialize(config = Dwf.configuration)
6
+ @config = config
7
+ end
8
+
3
9
  def find_job(workflow_id, job_name)
4
10
  job_name_match = /(?<klass>\w*[^-])-(?<identifier>.*)/.match(job_name)
5
11
  data = if job_name_match
@@ -94,7 +100,7 @@ module Dwf
94
100
  end
95
101
 
96
102
  def redis
97
- @redis ||= Redis.new
103
+ @redis ||= Redis.new(config.redis_opts)
98
104
  end
99
105
  end
100
106
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dwf
4
+ class Configuration
5
+ NAMESPACE = 'dwf'
6
+ REDIS_OPTS = { url: 'redis://localhost:6379' }.freeze
7
+
8
+ attr_accessor :redis_opts, :namespace
9
+
10
+ def initialize(hash = {})
11
+ @namespace = hash.fetch(:namespace, NAMESPACE)
12
+ @redis_opts = hash.fetch(:redis_url, REDIS_OPTS)
13
+ end
14
+ end
15
+ end
data/lib/dwf/item.rb CHANGED
@@ -1,10 +1,9 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require_relative 'client'
3
4
 
4
5
  module Dwf
5
6
  class Item
6
- DEFAULT_QUEUE = 'default'
7
-
8
7
  attr_reader :workflow_id, :id, :params, :queue, :klass, :started_at,
9
8
  :enqueued_at, :finished_at, :failed_at, :callback_type
10
9
  attr_accessor :incoming, :outgoing
@@ -13,7 +12,7 @@ module Dwf
13
12
  @workflow_id = options[:workflow_id]
14
13
  @id = options[:id]
15
14
  @params = options[:params]
16
- @queue = options[:queue] || DEFAULT_QUEUE
15
+ @queue = options[:queue]
17
16
  @incoming = options[:incoming] || []
18
17
  @outgoing = options[:outgoing] || []
19
18
  @klass = options[:klass] || self.class
@@ -41,7 +40,8 @@ module Dwf
41
40
  end
42
41
 
43
42
  def perform_async
44
- Dwf::Worker.set(queue: queue).perform_async(workflow_id, name)
43
+ Dwf::Worker.set(queue: queue || client.config.namespace)
44
+ .perform_async(workflow_id, name)
45
45
  end
46
46
 
47
47
  def name
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Dwf
4
+ VERSION = '0.1.7'
5
+ end
data/lib/dwf/worker.rb CHANGED
@@ -1,3 +1,5 @@
1
+ # frozen_string_literal: true
2
+
1
3
  require 'sidekiq'
2
4
  require_relative 'client'
3
5
 
data/lib/dwf.rb CHANGED
@@ -1,4 +1,5 @@
1
1
  # frozen_string_literal: true
2
+
2
3
  require "bundler/setup"
3
4
 
4
5
  require 'sidekiq'
@@ -12,8 +13,15 @@ require_relative 'dwf/item'
12
13
  require_relative 'dwf/client'
13
14
  require_relative 'dwf/worker'
14
15
  require_relative 'dwf/callback'
16
+ require_relative 'dwf/configuration'
15
17
 
16
18
  module Dwf
17
- VERSION = '0.1.6'
19
+ def self.configuration
20
+ @configuration ||= Configuration.new
21
+ end
22
+
23
+ def self.config
24
+ yield configuration
25
+ end
18
26
  end
19
27
 
@@ -0,0 +1,154 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+ require 'mock_redis'
5
+
6
+ describe Dwf::Client, client: true do
7
+ let(:client) { described_class.new }
8
+ let(:workflow_id) { SecureRandom.uuid }
9
+ let(:id) { SecureRandom.uuid }
10
+ let(:redis) { Redis.new }
11
+ before do
12
+ redis_instance = MockRedis.new
13
+ allow(Redis).to receive(:new).and_return redis_instance
14
+ end
15
+
16
+ describe '#find_job' do
17
+ let!(:job) do
18
+ j = Dwf::Item.new(workflow_id: workflow_id, id: id)
19
+ j.persist!
20
+ j
21
+ end
22
+
23
+ context 'find by item class name' do
24
+ it {
25
+ item = client.find_job(workflow_id, Dwf::Item.name)
26
+ expect(item.workflow_id).to eq workflow_id
27
+ expect(item.id).to eq id
28
+ expect(item.name).to eq job.name
29
+ }
30
+ end
31
+
32
+ context 'find by item name' do
33
+ it {
34
+ item = client.find_job(workflow_id, job.name)
35
+ expect(item.workflow_id).to eq workflow_id
36
+ expect(item.id).to eq id
37
+ expect(item.name).to eq job.name
38
+ }
39
+ end
40
+ end
41
+
42
+ describe '#persist_job' do
43
+ let!(:job) { Dwf::Item.new(workflow_id: workflow_id, id: id) }
44
+
45
+ it do
46
+ expect(redis.exists?("dwf.jobs.#{job.workflow_id}.#{job.klass}"))
47
+ .to be_falsy
48
+
49
+ client.persist_job(job)
50
+
51
+ expect(redis.exists?("dwf.jobs.#{job.workflow_id}.#{job.klass}"))
52
+ .to be_truthy
53
+ end
54
+ end
55
+
56
+ describe '#persist_workflow' do
57
+ let(:workflow) { Dwf::Workflow.new }
58
+
59
+ it do
60
+ expect(redis.exists?("dwf.workflows.#{workflow.id}")).to be_falsy
61
+ client.persist_workflow(workflow)
62
+ expect(redis.exists?("dwf.workflows.#{workflow.id}")).to be_truthy
63
+ end
64
+ end
65
+
66
+ describe '#check_or_lock' do
67
+ before do
68
+ allow_any_instance_of(described_class).to receive(:sleep)
69
+ end
70
+
71
+ context 'job is running' do
72
+ let(:job_name) { 'ahihi' }
73
+
74
+ before do
75
+ allow(client).to receive(:set)
76
+ redis.set("wf_enqueue_outgoing_jobs_#{workflow_id}-#{job_name}", 'running')
77
+ client.check_or_lock(workflow_id, job_name)
78
+ end
79
+
80
+ it { expect(client).not_to have_received(:set) }
81
+ end
82
+
83
+ context 'job is not running' do
84
+ let(:job_name) { 'ahihi' }
85
+
86
+ before do
87
+ allow(redis).to receive(:set)
88
+ client.check_or_lock(workflow_id, job_name)
89
+ end
90
+
91
+ it do
92
+ expect(redis).to have_received(:set)
93
+ .with("wf_enqueue_outgoing_jobs_#{workflow_id}-#{job_name}", 'running')
94
+ end
95
+ end
96
+ end
97
+
98
+ describe '#release_lock' do
99
+ before do
100
+ allow(redis).to receive(:del)
101
+ client.release_lock(workflow_id, 'ahihi')
102
+ end
103
+
104
+ it do
105
+ expect(redis).to have_received(:del)
106
+ .with("dwf_enqueue_outgoing_jobs_#{workflow_id}-ahihi")
107
+ end
108
+ end
109
+
110
+ describe '#build_job_id' do
111
+ before do
112
+ allow(redis).to receive(:hexists)
113
+ client.build_job_id(workflow_id, 'ahihi')
114
+ end
115
+
116
+ it { expect(redis).to have_received(:hexists) }
117
+ end
118
+
119
+ describe '#build_workflow_id' do
120
+ before do
121
+ allow(redis).to receive(:exists?)
122
+ client.build_workflow_id
123
+ end
124
+
125
+ it { expect(redis).to have_received(:exists?) }
126
+ end
127
+
128
+ describe '#key_exists?' do
129
+ before do
130
+ allow(redis).to receive(:exists?)
131
+ client.key_exists?('ahihi')
132
+ end
133
+
134
+ it { expect(redis).to have_received(:exists?).with('ahihi') }
135
+ end
136
+
137
+ describe '#set' do
138
+ before do
139
+ allow(redis).to receive(:set)
140
+ client.set('ahihi', 'a')
141
+ end
142
+
143
+ it { expect(redis).to have_received(:set).with('ahihi', 'a') }
144
+ end
145
+
146
+ describe '#delete' do
147
+ before do
148
+ allow(redis).to receive(:del)
149
+ client.delete('ahihi')
150
+ end
151
+
152
+ it { expect(redis).to have_received(:del).with('ahihi') }
153
+ end
154
+ end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ describe Dwf::Configuration, configuration: true do
6
+ let(:configuration) { described_class.new }
7
+
8
+ specify do
9
+ expect(configuration.namespace).to eq described_class::NAMESPACE
10
+ expect(configuration.redis_opts).to eq described_class::REDIS_OPTS
11
+ end
12
+ end
@@ -16,7 +16,7 @@ describe Dwf::Item, item: true do
16
16
  params: {},
17
17
  incoming: incoming,
18
18
  outgoing: outgoing,
19
- queue: Dwf::Item::DEFAULT_QUEUE,
19
+ queue: Dwf::Configuration::NAMESPACE,
20
20
  klass: 'Dwf::Item',
21
21
  started_at: started_at,
22
22
  finished_at: finished_at,
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.6
4
+ version: 0.1.7
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-06 00:00:00.000000000 Z
11
+ date: 2021-09-08 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: '3.2'
55
+ - !ruby/object:Gem::Dependency
56
+ name: mock_redis
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: 0.27.2
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: 0.27.2
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: sidekiq
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -86,10 +100,14 @@ files:
86
100
  - lib/dwf.rb
87
101
  - lib/dwf/callback.rb
88
102
  - lib/dwf/client.rb
103
+ - lib/dwf/configuration.rb
89
104
  - lib/dwf/item.rb
90
105
  - lib/dwf/utils.rb
106
+ - lib/dwf/version.rb
91
107
  - lib/dwf/worker.rb
92
108
  - lib/dwf/workflow.rb
109
+ - spec/dwf/client_spec.rb
110
+ - spec/dwf/configuration_spec.rb
93
111
  - spec/dwf/item_spec.rb
94
112
  - spec/dwf/utils_spec.rb
95
113
  - spec/spec_helper.rb
@@ -118,6 +136,8 @@ specification_version: 4
118
136
  summary: Gush cloned without ActiveJob but requried Sidekiq. This project is for researching
119
137
  DSL purpose
120
138
  test_files:
139
+ - spec/dwf/client_spec.rb
140
+ - spec/dwf/configuration_spec.rb
121
141
  - spec/dwf/item_spec.rb
122
142
  - spec/dwf/utils_spec.rb
123
143
  - spec/spec_helper.rb