nxt_pipeline 0.4.2 → 0.4.3

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: 0ddc6f3289300268adabdfda7f6b0a2c50561e9127f6951f0a29ebfb26d48298
4
- data.tar.gz: 13af4e35b2014025fb33d16bd9ed1cf74048d6e20404035c5001fedf7db18b02
3
+ metadata.gz: 0f47be27dd03af5d8a11274b4667a40e2a0c14b4be0a373dd90e1fc7deb93c03
4
+ data.tar.gz: 6964e21671bb458e187dd3289538e49243e42b06c38c804ffc2b69ed94146612
5
5
  SHA512:
6
- metadata.gz: c174e7fae2b76cb47b0b2bd1388ad50796603d49283c94056e5af96fbbf46d5d51c745c2cf09015967ac5aa92057f94ec3e6b86412e93686b6b1728db4058c7a
7
- data.tar.gz: b9e44023b319bd809e71b83eae038676f51e06aae032c40686ed9c1eee6ee9093b7fe38814c22db9139cf4e2ba5d2bfefeda258d70fb883a7a3e738e27429f46
6
+ metadata.gz: 5ba8339e42e2e485e9c0c00a35d6df56324b1145605d564039a4931d384d0297ef44b3613c8e45e83dfcfea83f0ed7b5a377f3a6e89f2a03e5b9dbfcc6e47b9a
7
+ data.tar.gz: f9c938b9302bf9f2b4c126ddaa1b978b99c2f02fe1cdbc6d17be307135a22a504e002c6b110fa0b2eb92a04b5623f4293c8f92575c82ad2240f3de0b4a49a8ad
@@ -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
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- nxt_pipeline (0.4.2)
4
+ nxt_pipeline (0.4.3)
5
5
  activesupport
6
6
 
7
7
  GEM
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
 
@@ -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
- mapper = options_mapper || default_options_mapper
27
- mapper_args = [changeset, self].take(mapper.arity)
28
- self.mapped_options = mapper.call(*mapper_args)
29
-
30
- guard_args = [changeset, self]
26
+ track_execution_time do
27
+ set_mapped_options(changeset)
28
+ guard_args = [changeset, self]
31
29
 
32
- if_guard_args = guard_args.take(if_guard.arity)
33
- unless_guard_guard_args = guard_args.take(unless_guard.arity)
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
- self.result = instrumentalize_callable(constructor, constructor_args)
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
- # def type?(potential_type)
51
- # constructor.resolve_type(potential_type)
52
- # end
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 instrumentalize_callable(callable, args)
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
- ->(changeset) { {} }
123
+ ->(_) { {} }
94
124
  end
95
125
  end
96
- end
126
+ end
@@ -1,4 +1,4 @@
1
1
  module NxtPipeline
2
- VERSION = "0.4.2".freeze
2
+ VERSION = "0.4.3".freeze
3
3
  end
4
4
 
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.2
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 00:00:00.000000000 Z
13
+ date: 2020-10-23 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: activesupport