nxt_pipeline 0.4.2 → 0.4.3
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 +4 -4
- data/CHANGELOG.md +7 -0
- data/Gemfile.lock +1 -1
- data/README.md +35 -32
- data/lib/nxt_pipeline/step.rb +54 -24
- data/lib/nxt_pipeline/version.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0f47be27dd03af5d8a11274b4667a40e2a0c14b4be0a373dd90e1fc7deb93c03
|
4
|
+
data.tar.gz: 6964e21671bb458e187dd3289538e49243e42b06c38c804ffc2b69ed94146612
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 5ba8339e42e2e485e9c0c00a35d6df56324b1145605d564039a4931d384d0297ef44b3613c8e45e83dfcfea83f0ed7b5a377f3a6e89f2a03e5b9dbfcc6e47b9a
|
7
|
+
data.tar.gz: f9c938b9302bf9f2b4c126ddaa1b978b99c2f02fe1cdbc6d17be307135a22a504e002c6b110fa0b2eb92a04b5623f4293c8f92575c82ad2240f3de0b4a49a8ad
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,10 @@
|
|
1
|
+
## nxt_pipeline 0.4.3 (October 20, 2020)
|
2
|
+
|
3
|
+
Add new attribute readers on step object.
|
4
|
+
|
5
|
+
After executing a step execution_finished_at execution_started_at and execution_duration
|
6
|
+
will be set and can be accessed via attribute readers.
|
7
|
+
|
1
8
|
## nxt_pipeline 0.4.2 (October 12, 2020)
|
2
9
|
|
3
10
|
* Fix bug when registering an error without passing arguments in which case the callback didn't get executed. More info: https://github.com/nxt-insurance/nxt_pipeline/issues/39
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -24,35 +24,35 @@ Or install it yourself as:
|
|
24
24
|
|
25
25
|
### Constructors
|
26
26
|
|
27
|
-
First you probably want to configure a pipeline so that it can execute your steps.
|
28
|
-
Therefore you want to define constructors for your steps. Constructors take a name
|
27
|
+
First you probably want to configure a pipeline so that it can execute your steps.
|
28
|
+
Therefore you want to define constructors for your steps. Constructors take a name
|
29
29
|
as the first argument and step options as the second. All step options are being exposed
|
30
|
-
by the step yielded to the constructor.
|
30
|
+
by the step yielded to the constructor.
|
31
31
|
|
32
32
|
```ruby
|
33
33
|
pipeline = NxtPipeline::Pipeline.new do |p|
|
34
34
|
# Add a named constructor that will be used to execute your steps later
|
35
35
|
# All options that you pass in your step will be available through accessors in your constructor
|
36
|
-
# You can call :to_s on a step to set it by default. You can later overwrite at execution for each step if needed.
|
36
|
+
# You can call :to_s on a step to set it by default. You can later overwrite at execution for each step if needed.
|
37
37
|
p.constructor(:service, default: true) do |step, arg:|
|
38
38
|
step.to_s = step.service_class.to_s
|
39
39
|
result = step.service_class.new(options: arg).call
|
40
40
|
result && { arg: result }
|
41
41
|
end
|
42
|
-
|
42
|
+
|
43
43
|
p.constructor(:job) do |step, arg:|
|
44
44
|
step.job_class.perform_later(*arg) && { arg: arg }
|
45
45
|
end
|
46
46
|
end
|
47
47
|
|
48
|
-
# Once a pipeline was created you can still configure it
|
48
|
+
# Once a pipeline was created you can still configure it
|
49
49
|
pipeline.constructor(:call) do |step, arg:|
|
50
50
|
result = step.caller.new(arg).call
|
51
51
|
result && { arg: result }
|
52
52
|
end
|
53
53
|
|
54
|
-
# same with block syntax
|
55
|
-
# You can use this to split up execution from configuration
|
54
|
+
# same with block syntax
|
55
|
+
# You can use this to split up execution from configuration
|
56
56
|
pipeline.configure do |p|
|
57
57
|
p.constructor(:call) do |step, arg:|
|
58
58
|
result = step.caller.new(arg).call
|
@@ -61,13 +61,13 @@ pipeline.configure do |p|
|
|
61
61
|
end
|
62
62
|
```
|
63
63
|
|
64
|
-
### Defining steps
|
64
|
+
### Defining steps
|
65
65
|
|
66
66
|
Once your pipeline knows how to execute your steps you can add those.
|
67
67
|
|
68
68
|
```ruby
|
69
69
|
pipeline.step :service, service_class: MyServiceClass, to_s: 'First step'
|
70
|
-
pipeline.step service_class: MyOtherServiceClass, to_s: 'Second step'
|
70
|
+
pipeline.step service_class: MyOtherServiceClass, to_s: 'Second step'
|
71
71
|
# ^ Since service is the default step you don't have to specify it the step type each time
|
72
72
|
pipeline.step :job, job_class: MyJobClass # to_s is optional
|
73
73
|
pipeline.step :job, job_class: MyOtherJobClass
|
@@ -82,12 +82,12 @@ end
|
|
82
82
|
```
|
83
83
|
|
84
84
|
You can also define inline steps, meaning the block will be executed. When you do not provide a :to_s option, type
|
85
|
-
will be used as :to_s option per default. When no type was given for an inline block the type of the inline block
|
86
|
-
will be set to :inline.
|
85
|
+
will be used as :to_s option per default. When no type was given for an inline block the type of the inline block
|
86
|
+
will be set to :inline.
|
87
87
|
|
88
88
|
### Execution
|
89
89
|
|
90
|
-
You can then execute the steps with:
|
90
|
+
You can then execute the steps with:
|
91
91
|
|
92
92
|
```ruby
|
93
93
|
pipeline.execute(arg: 'initial argument')
|
@@ -111,13 +111,13 @@ NxtPipeline::Pipeline.execute(arg: 'initial argument') do |p|
|
|
111
111
|
{ arg: arg.upcase }
|
112
112
|
end
|
113
113
|
end
|
114
|
-
```
|
114
|
+
```
|
115
115
|
|
116
|
-
You can query the steps of your pipeline simply by calling `pipeline.steps`. A NxtPipeline::Step will provide you with
|
117
|
-
an interface to it's type, options, status (:success, :skipped, :failed), result, error and the index in the pipeline.
|
116
|
+
You can query the steps of your pipeline simply by calling `pipeline.steps`. A NxtPipeline::Step will provide you with
|
117
|
+
an interface to it's type, options, status (:success, :skipped, :failed), execution_finished_at execution_started_at, execution_duration, result, error and the index in the pipeline.
|
118
118
|
|
119
119
|
```
|
120
|
-
pipeline.steps.first
|
120
|
+
pipeline.steps.first
|
121
121
|
# will give you something like this:
|
122
122
|
|
123
123
|
#<NxtPipeline::Step:0x00007f83eb399448
|
@@ -128,20 +128,23 @@ pipeline.steps.first
|
|
128
128
|
@opts={:to_s=>:transformer, :method=>:upcase},
|
129
129
|
@result=nil,
|
130
130
|
@status=nil,
|
131
|
-
@type=:transformer
|
132
|
-
|
131
|
+
@type=:transformer
|
132
|
+
@execution_duration=1.0e-05,
|
133
|
+
@execution_finished_at=2020-10-22 15:52:55.806417 +0100,
|
134
|
+
@execution_started_at=2020-10-22 15:52:55.806407 +0100,>
|
135
|
+
```
|
133
136
|
|
134
137
|
### Guard clauses
|
135
138
|
|
136
139
|
You can also define guard clauses that take a proc to prevent the execution of a step.
|
137
|
-
When the guard takes an argument the step argument is yielded.
|
140
|
+
When the guard takes an argument the step argument is yielded.
|
138
141
|
|
139
142
|
```ruby
|
140
143
|
pipeline.execute(arg: 'initial argument') do |p|
|
141
144
|
p.step :service, service_class: MyServiceClass, if: -> (arg:) { arg == 'initial argument' }
|
142
145
|
p.step :service, service_class: MyOtherServiceClass, unless: -> { false }
|
143
146
|
end
|
144
|
-
|
147
|
+
|
145
148
|
```
|
146
149
|
|
147
150
|
### Error callbacks
|
@@ -153,25 +156,25 @@ NxtPipeline::Pipeline.new do |p|
|
|
153
156
|
p.step do |_, arg:|
|
154
157
|
{ arg: arg.upcase }
|
155
158
|
end
|
156
|
-
|
159
|
+
|
157
160
|
p.on_error MyCustomError do |step, opts, error|
|
158
161
|
# First matching error callback will be executed!
|
159
162
|
end
|
160
|
-
|
163
|
+
|
161
164
|
p.on_errors ArgumentError, KeyError do |step, opts, error|
|
162
165
|
# First matching error callback will be executed!
|
163
166
|
end
|
164
|
-
|
167
|
+
|
165
168
|
p.on_errors YetAnotherError, halt_on_error: false do |step, opts, error|
|
166
169
|
# After executing the callback the pipeline will not halt but continue to
|
167
170
|
# execute the next steps.
|
168
171
|
end
|
169
|
-
|
172
|
+
|
170
173
|
p.on_errors do |step, opts, error|
|
171
174
|
# This will match all errors inheriting from StandardError
|
172
175
|
end
|
173
176
|
end
|
174
|
-
```
|
177
|
+
```
|
175
178
|
|
176
179
|
### Before and After callbacks
|
177
180
|
|
@@ -181,27 +184,27 @@ You can also define callbacks that run before and after the `#execute` action. B
|
|
181
184
|
NxtPipeline::Pipeline.new do |p|
|
182
185
|
p.before_execute do |pipeline, arg:|
|
183
186
|
# Will be called from within #execute before entering the first step
|
184
|
-
# After any configure block though!
|
187
|
+
# After any configure block though!
|
185
188
|
end
|
186
|
-
|
189
|
+
|
187
190
|
p.after_execute do |pipeline, arg:|
|
188
191
|
# Will be called from within #execute after executing last step
|
189
192
|
end
|
190
193
|
end
|
191
194
|
```
|
192
195
|
|
193
|
-
Note that the `after_execute` callback will not be called, when an error is raised in one of the steps. See the previous section (_Error callbacks_) for how to define callbacks that run in case of errors.
|
196
|
+
Note that the `after_execute` callback will not be called, when an error is raised in one of the steps. See the previous section (_Error callbacks_) for how to define callbacks that run in case of errors.
|
194
197
|
|
195
198
|
### Step resolvers
|
196
199
|
|
197
200
|
NxtPipeline is using so called step_resolvers to find the constructor for a given step by the arguments passed in.
|
198
|
-
You can also use this if you are not fine with resolving the constructor from the step argument. Check out the
|
199
|
-
`nxt_pipeline/spec/step_resolver_spec.rb` for examples how you can implement your own step_resolvers.
|
201
|
+
You can also use this if you are not fine with resolving the constructor from the step argument. Check out the
|
202
|
+
`nxt_pipeline/spec/step_resolver_spec.rb` for examples how you can implement your own step_resolvers.
|
200
203
|
|
201
204
|
|
202
205
|
## Topics
|
203
206
|
- Step orchestration (chainable steps)
|
204
|
-
- Constructors should take arg as first and step as second arg
|
207
|
+
- Constructors should take arg as first and step as second arg
|
205
208
|
|
206
209
|
## Development
|
207
210
|
|
data/lib/nxt_pipeline/step.rb
CHANGED
@@ -16,47 +16,57 @@ module NxtPipeline
|
|
16
16
|
@mapped_options = nil
|
17
17
|
end
|
18
18
|
|
19
|
-
attr_reader :argument, :result, :status, :error, :opts, :index, :mapped_options
|
19
|
+
attr_reader :argument, :result, :status, :execution_started_at, :execution_finished_at, :execution_duration, :error, :opts, :index, :mapped_options
|
20
20
|
attr_accessor :to_s
|
21
21
|
|
22
22
|
alias_method :name=, :to_s=
|
23
23
|
alias_method :name, :to_s
|
24
24
|
|
25
25
|
def execute(**changeset)
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
guard_args = [changeset, self]
|
26
|
+
track_execution_time do
|
27
|
+
set_mapped_options(changeset)
|
28
|
+
guard_args = [changeset, self]
|
31
29
|
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
if !instrumentalize_callable(unless_guard, unless_guard_guard_args) && instrumentalize_callable(if_guard, if_guard_args)
|
36
|
-
constructor_args = [self, changeset]
|
37
|
-
constructor_args = constructor_args.take(constructor.arity)
|
30
|
+
if evaluate_unless_guard(guard_args) && evaluate_if_guard(guard_args)
|
31
|
+
self.result = construct_result(changeset)
|
32
|
+
end
|
38
33
|
|
39
|
-
|
34
|
+
set_status
|
35
|
+
result
|
40
36
|
end
|
41
|
-
|
42
|
-
set_status
|
43
|
-
result
|
44
37
|
rescue StandardError => e
|
45
38
|
self.status = :failed
|
46
39
|
self.error = e
|
47
40
|
raise
|
48
41
|
end
|
49
42
|
|
50
|
-
|
51
|
-
|
52
|
-
|
43
|
+
def set_mapped_options(changeset)
|
44
|
+
mapper = options_mapper || default_options_mapper
|
45
|
+
mapper_args = [changeset, self].take(mapper.arity)
|
46
|
+
self.mapped_options = mapper.call(*mapper_args)
|
47
|
+
end
|
53
48
|
|
54
49
|
private
|
55
50
|
|
56
|
-
attr_writer :result, :status, :error, :mapped_options
|
51
|
+
attr_writer :result, :status, :error, :mapped_options, :execution_started_at, :execution_finished_at, :execution_duration
|
57
52
|
attr_reader :constructor, :options_mapper
|
58
|
-
|
59
|
-
def
|
53
|
+
|
54
|
+
def evaluate_if_guard(args)
|
55
|
+
execute_callable(if_guard, args)
|
56
|
+
end
|
57
|
+
|
58
|
+
def evaluate_unless_guard(args)
|
59
|
+
!execute_callable(unless_guard, args)
|
60
|
+
end
|
61
|
+
|
62
|
+
def construct_result(changeset)
|
63
|
+
args = [self, changeset]
|
64
|
+
execute_callable(constructor, args)
|
65
|
+
end
|
66
|
+
|
67
|
+
def execute_callable(callable, args)
|
68
|
+
args = args.take(callable.arity)
|
69
|
+
|
60
70
|
if args.last.is_a?(Hash)
|
61
71
|
callable.call(*args.take(args.length - 1), **args.last)
|
62
72
|
else
|
@@ -88,9 +98,29 @@ module NxtPipeline
|
|
88
98
|
self.status = result.present? ? :success : :skipped
|
89
99
|
end
|
90
100
|
|
101
|
+
def track_execution_time(&block)
|
102
|
+
set_execution_started_at
|
103
|
+
block.call
|
104
|
+
ensure
|
105
|
+
set_execution_finished_at
|
106
|
+
set_execution_duration
|
107
|
+
end
|
108
|
+
|
109
|
+
def set_execution_started_at
|
110
|
+
self.execution_started_at = Time.current
|
111
|
+
end
|
112
|
+
|
113
|
+
def set_execution_finished_at
|
114
|
+
self.execution_finished_at = Time.current
|
115
|
+
end
|
116
|
+
|
117
|
+
def set_execution_duration
|
118
|
+
self.execution_duration = execution_finished_at - execution_started_at
|
119
|
+
end
|
120
|
+
|
91
121
|
def default_options_mapper
|
92
122
|
# returns an empty hash
|
93
|
-
->(
|
123
|
+
->(_) { {} }
|
94
124
|
end
|
95
125
|
end
|
96
|
-
end
|
126
|
+
end
|
data/lib/nxt_pipeline/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: nxt_pipeline
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.4.
|
4
|
+
version: 0.4.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nils Sommer
|
@@ -10,7 +10,7 @@ authors:
|
|
10
10
|
autorequire:
|
11
11
|
bindir: exe
|
12
12
|
cert_chain: []
|
13
|
-
date: 2020-10-
|
13
|
+
date: 2020-10-23 00:00:00.000000000 Z
|
14
14
|
dependencies:
|
15
15
|
- !ruby/object:Gem::Dependency
|
16
16
|
name: activesupport
|