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 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