sidekiq_workflows 0.2.1

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 ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 4c14e767d390b989168bde7f4f5ecc2aa1ec385262a61ce658cf31a847468303
4
+ data.tar.gz: 2f961ee3f477b3b3c1301aaa73abfb62e6209f452416b8ce6a78e0af642e09f0
5
+ SHA512:
6
+ metadata.gz: 8888cb766690ac12aa05b37fdfd3eac761619334f8b65e73e6ea8f966c9b660218defd3467d4498f5b10115717c36f031016a6087d554f515d6762b8073e795d
7
+ data.tar.gz: 7dfd4071261df7b8cea4416592a5791bea584e787dd22c6d4b2d03df24652fc45a0fd3b486afa0be3f2c7df27dad864185e71ba3d264bc27077f94e7a01e4a63
data/Rakefile ADDED
@@ -0,0 +1,13 @@
1
+ require 'rake/testtask'
2
+ require 'rubygems/package_task'
3
+
4
+ Rake::TestTask.new do |t|
5
+ t.libs << 'lib'
6
+ t.test_files = FileList.new('test/**/*_test.rb')
7
+ end
8
+
9
+ s = Gem::Specification.load("sidekiq_workflows.gemspec")
10
+
11
+ Gem::PackageTask.new s do end
12
+
13
+ task default: %w[test]
@@ -0,0 +1,34 @@
1
+ require 'json'
2
+ require 'sidekiq-pro'
3
+
4
+ module SidekiqWorkflows
5
+ class << self
6
+ attr_accessor :worker_queue
7
+ attr_accessor :callback_queue
8
+ end
9
+
10
+ require 'sidekiq_workflows/node'
11
+ require 'sidekiq_workflows/root_node'
12
+ require 'sidekiq_workflows/worker_node'
13
+ require 'sidekiq_workflows/builder'
14
+ require 'sidekiq_workflows/worker'
15
+
16
+ def self.deserialize(string)
17
+ from_h(JSON.parse(string, symbolize_names: true))
18
+ end
19
+
20
+ def self.from_h(hash, parent = nil)
21
+ parent ||= hash.key?(:workers) ? WorkerNode.new(workflow_uuid: hash[:workflow_uuid], on_partial_complete: hash[:on_partial_complete], workers: hash[:workers]) : RootNode.new(workflow_uuid: hash[:workflow_uuid], on_partial_complete: hash[:on_partial_complete])
22
+ hash[:children].each do |h|
23
+ child = parent.add_group(h[:workers])
24
+ from_h(h, child)
25
+ end
26
+ parent
27
+ end
28
+
29
+ def self.build(workflow_uuid: nil, on_partial_complete: nil, except: [], &block)
30
+ root = RootNode.new(workflow_uuid: workflow_uuid, on_partial_complete: on_partial_complete)
31
+ Builder.new(root, except).then(&block)
32
+ root
33
+ end
34
+ end
@@ -0,0 +1,26 @@
1
+ require 'sidekiq_workflows/node'
2
+
3
+ module SidekiqWorkflows
4
+ class Builder
5
+ attr_reader :node, :skip_workers
6
+
7
+ def initialize(node, skip_workers = [])
8
+ @node = node
9
+ @skip_workers = skip_workers
10
+ end
11
+
12
+ def perform(workers, *args, delay: nil)
13
+ workers = [worker: workers, payload: args, delay: delay] unless workers.is_a?(Array)
14
+ workers.reject! { |w| skip_workers.include?(w[:worker]) }
15
+ return self if workers.empty?
16
+
17
+ child = @node.add_group(workers)
18
+ Builder.new(child, skip_workers)
19
+ end
20
+
21
+ def then(&block)
22
+ instance_eval(&block)
23
+ end
24
+ end
25
+
26
+ end
@@ -0,0 +1,16 @@
1
+ module SidekiqWorkflows
2
+ module Node
3
+ def add_group(workers)
4
+ @children << (child = WorkerNode.new(workers: workers, workflow_uuid: workflow_uuid, on_partial_complete: on_partial_complete, parent: self))
5
+ child
6
+ end
7
+
8
+ def serialize
9
+ to_h.to_json
10
+ end
11
+
12
+ def all_nodes
13
+ [self] + children.flat_map(&:all_nodes)
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,24 @@
1
+ require 'sidekiq_workflows/node'
2
+
3
+ module SidekiqWorkflows
4
+ class RootNode
5
+ include Node
6
+
7
+ attr_accessor :workflow_uuid, :on_partial_complete
8
+ attr_reader :children
9
+
10
+ def initialize(workflow_uuid: nil, on_partial_complete: nil)
11
+ @workflow_uuid = workflow_uuid
12
+ @on_partial_complete = on_partial_complete
13
+ @children = []
14
+ end
15
+
16
+ def to_h
17
+ {
18
+ workflow_uuid: workflow_uuid,
19
+ on_partial_complete: on_partial_complete,
20
+ children: @children.map(&:to_h)
21
+ }
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,78 @@
1
+ require 'sidekiq_workflows/node'
2
+
3
+ module SidekiqWorkflows
4
+ class Worker
5
+ include Sidekiq::Worker
6
+
7
+ sidekiq_options retry: false
8
+
9
+ def perform(workflow)
10
+ workflow = ensure_deserialized(workflow)
11
+
12
+ case workflow.class.name
13
+ when 'SidekiqWorkflows::RootNode'
14
+ perform_children(batch, workflow)
15
+ when 'SidekiqWorkflows::WorkerNode'
16
+ batch.jobs do
17
+ child_batch = Sidekiq::Batch.new
18
+ child_batch.callback_queue = SidekiqWorkflows.callback_queue unless SidekiqWorkflows.callback_queue.nil?
19
+ child_batch.description = "Workflow #{workflow.workflow_uuid || '-'}"
20
+ child_batch.on(:complete, 'SidekiqWorkflows::Worker#on_complete', workflow: workflow.serialize, workflow_uuid: workflow.workflow_uuid)
21
+ child_batch.jobs do
22
+ workflow.workers.each do |entry|
23
+ if entry[:delay]
24
+ entry[:worker].perform_in(entry[:delay], *entry[:payload])
25
+ else
26
+ entry[:worker].perform_async(*entry[:payload])
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ def on_complete(status, options)
35
+ workflow = ensure_deserialized(options['workflow'])
36
+
37
+ if workflow.on_partial_complete
38
+ klass, method = workflow.on_partial_complete.split('#')
39
+ ActiveSupport::Inflector.constantize(klass).new.send(method, status, options)
40
+ end
41
+
42
+ perform_children(status.parent_batch, workflow) unless status.failures > 0
43
+ end
44
+
45
+ def self.perform_async(workflow, *args)
46
+ set(queue: worker_queue).send(:perform_async, workflow.serialize, *args)
47
+ end
48
+
49
+ def self.perform_workflow(workflow, on_complete: nil, on_complete_options: {})
50
+ batch = Sidekiq::Batch.new
51
+ batch.callback_queue = SidekiqWorkflows.callback_queue unless SidekiqWorkflows.callback_queue.nil?
52
+ batch.description = "Workflow #{workflow.workflow_uuid || '-'} root batch"
53
+ batch.on(:complete, on_complete, on_complete_options.merge(workflow_uuid: workflow.workflow_uuid)) if on_complete
54
+ batch.jobs do
55
+ perform_async(workflow)
56
+ end
57
+ batch.bid
58
+ end
59
+
60
+ private
61
+
62
+ def self.worker_queue
63
+ SidekiqWorkflows.worker_queue || Sidekiq.default_worker_options['queue']
64
+ end
65
+
66
+ def perform_children(batch, workflow)
67
+ batch.jobs do
68
+ workflow.children.each do |child|
69
+ self.class.perform_async(child)
70
+ end
71
+ end
72
+ end
73
+
74
+ def ensure_deserialized(workflow)
75
+ workflow.is_a?(String) ? SidekiqWorkflows.deserialize(workflow) : workflow
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,38 @@
1
+ require 'sidekiq_workflows/node'
2
+ require 'active_support/inflector'
3
+
4
+ module SidekiqWorkflows
5
+ class WorkerNode
6
+ include Node
7
+
8
+ attr_accessor :workers, :workflow_uuid, :on_partial_complete
9
+ attr_reader :children
10
+ attr_reader :parent
11
+
12
+ def initialize(workers:, workflow_uuid: nil, on_partial_complete: nil, parent: nil)
13
+ @workers = workers.each do |entry|
14
+ entry[:worker] = ActiveSupport::Inflector.constantize(entry[:worker]) if entry[:worker].is_a?(String)
15
+ entry[:delay] = entry[:delay].to_i if entry[:delay]
16
+ end
17
+ @workflow_uuid = workflow_uuid
18
+ @on_partial_complete = on_partial_complete
19
+ @parent = parent
20
+ @children = []
21
+ end
22
+
23
+ def to_h
24
+ {
25
+ workers: workers.map do |entry|
26
+ {
27
+ worker: entry[:worker].name,
28
+ payload: entry[:payload],
29
+ delay: entry[:delay]
30
+ }
31
+ end,
32
+ workflow_uuid: workflow_uuid,
33
+ on_partial_complete: on_partial_complete,
34
+ children: @children.map(&:to_h)
35
+ }
36
+ end
37
+ end
38
+ end
metadata ADDED
@@ -0,0 +1,145 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sidekiq_workflows
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.2.1
5
+ platform: ruby
6
+ authors:
7
+ - Marian Theisen
8
+ - Christian Semmler
9
+ - Patrick Detlefsen
10
+ autorequire:
11
+ bindir: bin
12
+ cert_chain: []
13
+ date: 2018-08-31 00:00:00.000000000 Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: sidekiq-pro
17
+ requirement: !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - "~>"
20
+ - !ruby/object:Gem::Version
21
+ version: '4.0'
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: 4.0.2
25
+ type: :runtime
26
+ prerelease: false
27
+ version_requirements: !ruby/object:Gem::Requirement
28
+ requirements:
29
+ - - "~>"
30
+ - !ruby/object:Gem::Version
31
+ version: '4.0'
32
+ - - ">="
33
+ - !ruby/object:Gem::Version
34
+ version: 4.0.2
35
+ - !ruby/object:Gem::Dependency
36
+ name: activesupport
37
+ requirement: !ruby/object:Gem::Requirement
38
+ requirements:
39
+ - - "~>"
40
+ - !ruby/object:Gem::Version
41
+ version: '5.0'
42
+ type: :runtime
43
+ prerelease: false
44
+ version_requirements: !ruby/object:Gem::Requirement
45
+ requirements:
46
+ - - "~>"
47
+ - !ruby/object:Gem::Version
48
+ version: '5.0'
49
+ - !ruby/object:Gem::Dependency
50
+ name: rake
51
+ requirement: !ruby/object:Gem::Requirement
52
+ requirements:
53
+ - - "~>"
54
+ - !ruby/object:Gem::Version
55
+ version: '12.0'
56
+ type: :development
57
+ prerelease: false
58
+ version_requirements: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - "~>"
61
+ - !ruby/object:Gem::Version
62
+ version: '12.0'
63
+ - !ruby/object:Gem::Dependency
64
+ name: mocha
65
+ requirement: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - "~>"
68
+ - !ruby/object:Gem::Version
69
+ version: '1.3'
70
+ type: :development
71
+ prerelease: false
72
+ version_requirements: !ruby/object:Gem::Requirement
73
+ requirements:
74
+ - - "~>"
75
+ - !ruby/object:Gem::Version
76
+ version: '1.3'
77
+ - !ruby/object:Gem::Dependency
78
+ name: minitest
79
+ requirement: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - "~>"
82
+ - !ruby/object:Gem::Version
83
+ version: '5.0'
84
+ type: :development
85
+ prerelease: false
86
+ version_requirements: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - "~>"
89
+ - !ruby/object:Gem::Version
90
+ version: '5.0'
91
+ - !ruby/object:Gem::Dependency
92
+ name: pry
93
+ requirement: !ruby/object:Gem::Requirement
94
+ requirements:
95
+ - - "~>"
96
+ - !ruby/object:Gem::Version
97
+ version: 0.11.3
98
+ type: :development
99
+ prerelease: false
100
+ version_requirements: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - "~>"
103
+ - !ruby/object:Gem::Version
104
+ version: 0.11.3
105
+ description: Sidekiq extension providing a workflow API on top of Sidekiq Pro's batches
106
+ email:
107
+ - mt@zeit.io
108
+ - mail@csemmler.com
109
+ - pd@zeit.io
110
+ executables: []
111
+ extensions: []
112
+ extra_rdoc_files: []
113
+ files:
114
+ - Rakefile
115
+ - lib/sidekiq_workflows.rb
116
+ - lib/sidekiq_workflows/builder.rb
117
+ - lib/sidekiq_workflows/node.rb
118
+ - lib/sidekiq_workflows/root_node.rb
119
+ - lib/sidekiq_workflows/worker.rb
120
+ - lib/sidekiq_workflows/worker_node.rb
121
+ homepage: https://github.com/easymarketing/sidekiq_workflows
122
+ licenses:
123
+ - MIT
124
+ metadata: {}
125
+ post_install_message:
126
+ rdoc_options: []
127
+ require_paths:
128
+ - lib
129
+ required_ruby_version: !ruby/object:Gem::Requirement
130
+ requirements:
131
+ - - ">="
132
+ - !ruby/object:Gem::Version
133
+ version: '0'
134
+ required_rubygems_version: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - ">="
137
+ - !ruby/object:Gem::Version
138
+ version: '0'
139
+ requirements: []
140
+ rubyforge_project:
141
+ rubygems_version: 2.7.7
142
+ signing_key:
143
+ specification_version: 4
144
+ summary: Sidekiq extension providing a workflow API on top of Sidekiq Pro's batches
145
+ test_files: []