senro_usecaser 0.2.0 → 0.4.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.
@@ -89,30 +89,14 @@ module SenroUsecaser
89
89
  # organize StepA, StepB
90
90
  # end
91
91
  class Base
92
- # Declares a dependency to be injected from the container
93
- #
94
- # : (Symbol, ?Class) -> void
95
- def self.depends_on: (Symbol, ?Class) -> void
96
-
97
- # Returns the list of declared dependencies
98
- #
99
- # : () -> Array[Symbol]
100
- def self.dependencies: () -> Array[Symbol]
92
+ extend DependsOn
101
93
 
102
- # Returns the dependency type mapping
103
- #
104
- # : () -> Hash[Symbol, Class]
105
- def self.dependency_types: () -> Hash[Symbol, Class]
106
-
107
- # Sets the namespace for dependency resolution
108
- #
109
- # : ((Symbol | String)) -> void
110
- def self.namespace: (Symbol | String) -> void
94
+ include DependsOn::InstanceMethods
111
95
 
112
- # Returns the declared namespace
96
+ # Alias for backward compatibility
113
97
  #
114
98
  # : () -> (Symbol | String)?
115
- attr_reader use_case_namespace: untyped
99
+ alias self.use_case_namespace self.declared_namespace
116
100
 
117
101
  # Declares a sequence of UseCases to execute as a pipeline
118
102
  #
@@ -188,15 +172,98 @@ module SenroUsecaser
188
172
  # : () -> Array[Proc]
189
173
  def self.around_hooks: () -> Array[Proc]
190
174
 
191
- # Declares the expected input type for this UseCase
175
+ # Adds an on_failure hook
176
+ #
177
+ # : () { (untyped, Result[untyped], ?RetryContext?) -> void } -> void
178
+ def self.on_failure: () { (untyped, Result[untyped], ?RetryContext?) -> void } -> void
179
+
180
+ # Returns the list of on_failure hooks
181
+ #
182
+ # : () -> Array[Proc]
183
+ def self.on_failure_hooks: () -> Array[Proc]
184
+
185
+ # Configures automatic retry for specific error types
186
+ #
187
+ # @example Retry on network errors
188
+ # retry_on :network_error, attempts: 3, wait: 1
189
+ #
190
+ # @example Retry on exception class
191
+ # retry_on Net::OpenTimeout, attempts: 5, wait: 2, backoff: :exponential
192
+ #
193
+ # @example Multiple error types with jitter
194
+ # retry_on :rate_limited, :timeout, attempts: 3, wait: 1, jitter: 0.1
195
+ #
196
+ # rubocop:disable Metrics/ParameterLists
197
+ # : (*(Symbol | Class), ?attempts: Integer, ?wait: (Float | Integer),
198
+ # : ?backoff: Symbol, ?max_wait: (Float | Integer)?, ?jitter: (Float | Integer)) -> void
199
+ def self.retry_on: (*untyped error_matchers, ?attempts: untyped, ?wait: untyped, ?backoff: untyped, ?max_wait: untyped, ?jitter: untyped) -> untyped
200
+
201
+ # Returns the list of retry configurations
202
+ #
203
+ # : () -> Array[RetryConfiguration]
204
+ def self.retry_configurations: () -> Array[RetryConfiguration]
205
+
206
+ # Configures errors that should immediately discard (no retry)
207
+ #
208
+ # @example Discard on validation errors
209
+ # discard_on :validation_error, :not_found
210
+ #
211
+ # @example Discard on exception class
212
+ # discard_on ArgumentError
192
213
  #
193
- # : (Class) -> void
194
- def self.input: (Class) -> void
214
+ # : (*(Symbol | Class)) -> void
215
+ def self.discard_on: (*Symbol | Class) -> void
195
216
 
196
- # Returns the input class
217
+ # Returns the list of discard matchers
197
218
  #
198
- # : () -> Class?
199
- attr_reader input_class: untyped
219
+ # : () -> Array[(Symbol | Class)]
220
+ def self.discard_matchers: () -> Array[Symbol | Class]
221
+
222
+ # Adds a before_retry hook
223
+ #
224
+ # : () { (untyped, Result[untyped], RetryContext) -> void } -> void
225
+ def self.before_retry: () { (untyped, Result[untyped], RetryContext) -> void } -> void
226
+
227
+ # Returns the list of before_retry hooks
228
+ #
229
+ # : () -> Array[Proc]
230
+ def self.before_retry_hooks: () -> Array[Proc]
231
+
232
+ # Adds an after_retries_exhausted hook
233
+ #
234
+ # : () { (untyped, Result[untyped], RetryContext) -> void } -> void
235
+ def self.after_retries_exhausted: () { (untyped, Result[untyped], RetryContext) -> void } -> void
236
+
237
+ # Returns the list of after_retries_exhausted hooks
238
+ #
239
+ # : () -> Array[Proc]
240
+ def self.after_retries_exhausted_hooks: () -> Array[Proc]
241
+
242
+ # Declares the expected input type(s) for this UseCase
243
+ # Accepts a Class or one or more Modules that input must include
244
+ #
245
+ # @example Single class
246
+ # input UserInput
247
+ #
248
+ # @example Single module (interface)
249
+ # input HasUserId
250
+ #
251
+ # @example Multiple modules (interfaces)
252
+ # input HasUserId, HasEmail
253
+ #
254
+ # : (*Module) -> void
255
+ def self.input: (*Module) -> void
256
+
257
+ # Returns the input types as an array
258
+ #
259
+ # : () -> Array[Module]
260
+ def self.input_types: () -> Array[Module]
261
+
262
+ # Returns the input class (for backwards compatibility)
263
+ # If a Class is specified, returns it. Otherwise returns the first type.
264
+ #
265
+ # : () -> Module?
266
+ def self.input_class: () -> Module?
200
267
 
201
268
  # Declares the expected output type for this UseCase
202
269
  #
@@ -245,6 +312,18 @@ module SenroUsecaser
245
312
  # : (?untyped input) -> Result[untyped]
246
313
  def call: (?untyped input) -> Result[untyped]
247
314
 
315
+ # Represents a record of a step execution in a pipeline
316
+ class StepExecutionRecord < Struct[untyped]
317
+ attr_accessor step(): untyped
318
+
319
+ attr_accessor input(): untyped
320
+
321
+ attr_accessor result(): untyped
322
+
323
+ def self.new: (?step: untyped, ?input: untyped, ?result: untyped) -> instance
324
+ | ({ ?step: untyped, ?input: untyped, ?result: untyped }) -> instance
325
+ end
326
+
248
327
  private
249
328
 
250
329
  # Creates a success Result with the given value
@@ -267,11 +346,54 @@ module SenroUsecaser
267
346
  # : [T] (*Class, ?code: Symbol) { () -> T } -> Result[T]
268
347
  def capture: [T] (*Class, ?code: Symbol) { () -> T } -> Result[T]
269
348
 
349
+ # Validates that input satisfies all declared input types
350
+ # For Modules: checks if input's class includes the module
351
+ # For Classes: checks if input is an instance of the class
352
+ #
353
+ # : (untyped) -> void
354
+ def validate_input!: (untyped) -> void
355
+
356
+ # Validates that the result's value satisfies the declared output type
357
+ # Only validates if result is success and output_schema is a Class
358
+ #
359
+ # : (Result[untyped]) -> void
360
+ def validate_output!: (Result[untyped]) -> void
361
+
270
362
  # Executes the core logic with before/after/around hooks
271
363
  #
272
364
  # : (untyped) { () -> Result[untyped] } -> Result[untyped]
273
365
  def execute_with_hooks: (untyped) { () -> Result[untyped] } -> Result[untyped]
274
366
 
367
+ # Executes the UseCase with retry support
368
+ #
369
+ # : (untyped) -> Result[untyped]
370
+ def execute_with_retry: (untyped) -> Result[untyped]
371
+
372
+ # Builds a retry context with max attempts from configurations
373
+ #
374
+ # : () -> RetryContext
375
+ def build_retry_context: () -> RetryContext
376
+
377
+ # Finds a retry configuration that matches the result
378
+ #
379
+ # : (Result[untyped]) -> RetryConfiguration?
380
+ def find_matching_retry_config: (Result[untyped]) -> RetryConfiguration?
381
+
382
+ # Checks if the result should be discarded (no retry)
383
+ #
384
+ # : (Result[untyped]) -> bool
385
+ def should_discard?: (Result[untyped]) -> bool
386
+
387
+ # Runs before_retry hooks
388
+ #
389
+ # : (untyped, Result[untyped], RetryContext) -> void
390
+ def run_before_retry_hooks: (untyped, Result[untyped], RetryContext) -> void
391
+
392
+ # Runs after_retries_exhausted hooks
393
+ #
394
+ # : (untyped, Result[untyped], RetryContext) -> void
395
+ def run_after_retries_exhausted_hooks: (untyped, Result[untyped], RetryContext) -> void
396
+
275
397
  # Wraps a non-Result value in Result.success
276
398
  #
277
399
  # : (untyped) -> Result[untyped]
@@ -307,6 +429,16 @@ module SenroUsecaser
307
429
  # : (untyped, Result[untyped]) -> void
308
430
  def run_after_hooks: (untyped, Result[untyped]) -> void
309
431
 
432
+ # Runs all on_failure hooks when result is a failure
433
+ #
434
+ # : (untyped, Result[untyped], ?RetryContext?) -> void
435
+ def run_on_failure_hooks: (untyped, Result[untyped], ?RetryContext?) -> void
436
+
437
+ # Calls an on_failure hook with appropriate arguments
438
+ #
439
+ # : (untyped, Symbol, untyped, Result[untyped], RetryContext?) -> void
440
+ def call_on_failure_hook: (untyped, Symbol, untyped, Result[untyped], RetryContext?) -> void
441
+
310
442
  # Returns instantiated hook objects
311
443
  #
312
444
  # : () -> Array[Hook]
@@ -323,20 +455,11 @@ module SenroUsecaser
323
455
  def resolve_dependencies: (Container, Hash[Symbol, untyped]) -> void
324
456
 
325
457
  # Resolves a single dependency from the container
458
+ # Overrides DependsOn::InstanceMethods to accept container as parameter
326
459
  #
327
460
  # : (Container, Symbol) -> untyped
328
461
  def resolve_from_container: (Container, Symbol) -> untyped
329
462
 
330
- # Returns the effective namespace for dependency resolution
331
- #
332
- # : () -> (Symbol | String)?
333
- def effective_namespace: () -> (Symbol | String)?
334
-
335
- # Infers namespace from the class's module structure
336
- #
337
- # : () -> String?
338
- def infer_namespace_from_class: () -> String?
339
-
340
463
  # Executes the organized UseCase pipeline
341
464
  #
342
465
  # : (untyped) -> Result[untyped]
@@ -378,9 +501,28 @@ module SenroUsecaser
378
501
  def step_should_stop?: (Step) -> bool
379
502
 
380
503
  # Calls a single UseCase in the pipeline
381
- # Requires input_class to be defined for pipeline steps
504
+ # Requires input type(s) to be defined for pipeline steps
505
+ # Note: on_failure hooks are not called here - they're called in pipeline rollback
382
506
  #
383
507
  # : (singleton(Base), untyped) -> Result[untyped]
384
508
  def call_use_case: (singleton(Base), untyped) -> Result[untyped]
509
+
510
+ # Performs the UseCase as a pipeline step (without on_failure hooks)
511
+ # on_failure hooks are handled by the pipeline's rollback mechanism instead
512
+ #
513
+ # : (untyped, ?capture_exceptions: bool) -> Result[untyped]
514
+ def perform_as_pipeline_step: (untyped, ?capture_exceptions: bool) -> Result[untyped]
515
+
516
+ # Executes rollback by calling on_failure hooks on executed steps in reverse order
517
+ # Unlike run_on_failure_hooks, this method calls hooks regardless of result status
518
+ # because we want to rollback even successfully completed steps when pipeline fails
519
+ #
520
+ # : (Array[StepExecutionRecord]) -> void
521
+ def execute_pipeline_rollback: (Array[StepExecutionRecord]) -> void
522
+
523
+ # Runs on_failure hooks for rollback purposes (regardless of result status)
524
+ #
525
+ # : (untyped, Result[untyped]) -> void
526
+ def run_rollback_hooks: (untyped, Result[untyped]) -> void
385
527
  end
386
528
  end
@@ -0,0 +1,197 @@
1
+ # Generated from lib/senro_usecaser/depends_on.rb with RBS::Inline
2
+
3
+ module SenroUsecaser
4
+ # Module that provides dependency injection support
5
+ #
6
+ # This module can be extended into any class to enable the full DI functionality
7
+ # similar to UseCase and Hook classes, including:
8
+ # - `depends_on` for declaring dependencies
9
+ # - `namespace` for scoped dependency resolution
10
+ # - Automatic `infer_namespace_from_module` support
11
+ # - Default `initialize` that sets up dependency injection (uses SenroUsecaser.container if not provided)
12
+ #
13
+ # @example Basic usage (no initialize needed)
14
+ # class MyService
15
+ # extend SenroUsecaser::DependsOn
16
+ #
17
+ # depends_on :logger, Logger
18
+ # depends_on :repository
19
+ #
20
+ # # No initialize needed! Default is provided automatically.
21
+ #
22
+ # def perform
23
+ # logger.info("Performing...")
24
+ # repository.find(1)
25
+ # end
26
+ # end
27
+ #
28
+ # service = MyService.new # Uses SenroUsecaser.container
29
+ # service.logger # => Logger instance
30
+ #
31
+ # @example Custom initialize with super
32
+ # class MyService
33
+ # extend SenroUsecaser::DependsOn
34
+ #
35
+ # depends_on :logger
36
+ # attr_reader :extra
37
+ #
38
+ # def initialize(extra:, container: nil)
39
+ # super(container: container) # Handles dependency resolution
40
+ # @extra = extra
41
+ # end
42
+ # end
43
+ #
44
+ # @example With explicit namespace
45
+ # class Admin::UserService
46
+ # extend SenroUsecaser::DependsOn
47
+ #
48
+ # namespace :admin
49
+ # depends_on :user_repository, UserRepository
50
+ # end
51
+ #
52
+ # @example With infer_namespace_from_module (when configured)
53
+ # # When SenroUsecaser.configuration.infer_namespace_from_module = true
54
+ # class Admin::Orders::ProcessService
55
+ # extend SenroUsecaser::DependsOn
56
+ #
57
+ # depends_on :order_repository # resolved from "admin::orders" namespace
58
+ # end
59
+ module DependsOn
60
+ # Hook called when module is extended into a class
61
+ # Automatically includes InstanceMethods
62
+ def self.extended: (untyped base) -> untyped
63
+
64
+ # Declares a dependency to be injected from the container
65
+ #
66
+ # @param name [Symbol] The name of the dependency
67
+ # @param type [Class, nil] Optional expected type for the dependency
68
+ #
69
+ # @example Basic dependency
70
+ # depends_on :logger
71
+ #
72
+ # @example Typed dependency
73
+ # depends_on :repository, UserRepository
74
+ #
75
+ # : (Symbol, ?Class) -> void
76
+ def depends_on: (Symbol, ?Class) -> void
77
+
78
+ # Returns the list of declared dependencies
79
+ #
80
+ # : () -> Array[Symbol]
81
+ def dependencies: () -> Array[Symbol]
82
+
83
+ # Returns the dependency type mapping
84
+ #
85
+ # : () -> Hash[Symbol, Class]
86
+ def dependency_types: () -> Hash[Symbol, Class]
87
+
88
+ # Sets or returns the namespace for dependency resolution
89
+ #
90
+ # @param name [Symbol, String, nil] The namespace to set
91
+ # @return [Symbol, String, nil] The current namespace when no argument given
92
+ #
93
+ # @example Setting namespace
94
+ # namespace :admin
95
+ #
96
+ # @example Getting namespace
97
+ # current_ns = namespace
98
+ #
99
+ # : (?(Symbol | String)) -> (Symbol | String)?
100
+ def namespace: (?Symbol | String) -> (Symbol | String)?
101
+
102
+ # Returns the declared namespace
103
+ #
104
+ # : () -> (Symbol | String)?
105
+ def declared_namespace: () -> (Symbol | String)?
106
+
107
+ # Copies dependency configuration to a subclass
108
+ #
109
+ # @param subclass [Class] The subclass to copy dependencies to
110
+ #
111
+ # @example In inherited hook
112
+ # def self.inherited(subclass)
113
+ # super
114
+ # copy_depends_on_to(subclass)
115
+ # end
116
+ #
117
+ # : (Class) -> void
118
+ def copy_depends_on_to: (Class) -> void
119
+
120
+ # Instance methods for dependency resolution
121
+ #
122
+ # These methods are automatically included when DependsOn is extended.
123
+ # They require @_container and @_dependencies instance variables to be set.
124
+ module InstanceMethods
125
+ # Default initialize for classes using DependsOn
126
+ #
127
+ # This provides a default initialize that sets up dependency injection.
128
+ # Classes can override this and call super to extend the behavior.
129
+ #
130
+ # @param container [Container, nil] The DI container to resolve dependencies from.
131
+ # If nil, uses SenroUsecaser.container.
132
+ #
133
+ # @example Default usage (no arguments needed)
134
+ # class MyService
135
+ # extend SenroUsecaser::DependsOn
136
+ # depends_on :logger
137
+ # end
138
+ # service = MyService.new # Uses SenroUsecaser.container
139
+ #
140
+ # @example With explicit container
141
+ # service = MyService.new(container: custom_container)
142
+ #
143
+ # @example Custom initialize with super
144
+ # class MyService
145
+ # extend SenroUsecaser::DependsOn
146
+ # depends_on :logger
147
+ # attr_reader :extra
148
+ #
149
+ # def initialize(extra:, container: nil)
150
+ # super(container: container)
151
+ # @extra = extra
152
+ # end
153
+ # end
154
+ #
155
+ # : (?container: Container?) -> void
156
+ def initialize: (?container: Container?) -> void
157
+
158
+ # Resolves all declared dependencies from the container
159
+ #
160
+ # Call this in your initialize method after setting @_container and @_dependencies.
161
+ #
162
+ # @example
163
+ # def initialize(container:)
164
+ # @_container = container
165
+ # @_dependencies = {}
166
+ # resolve_dependencies
167
+ # end
168
+ #
169
+ # : () -> void
170
+ def resolve_dependencies: () -> void
171
+
172
+ private
173
+
174
+ # Returns the effective namespace for dependency resolution
175
+ #
176
+ # Priority:
177
+ # 1. Explicitly declared namespace via `namespace :name`
178
+ # 2. Inferred namespace from module structure (if configured)
179
+ #
180
+ # : () -> (Symbol | String)?
181
+ def effective_namespace: () -> (Symbol | String)?
182
+
183
+ # Infers namespace from the class's module structure
184
+ #
185
+ # Converts CamelCase module names to snake_case and joins with "::"
186
+ # e.g., Admin::Orders::ProcessService -> "admin::orders"
187
+ #
188
+ # : () -> String?
189
+ def infer_namespace_from_class: () -> String?
190
+
191
+ # Resolves a single dependency from the container
192
+ #
193
+ # : (Symbol) -> untyped
194
+ def resolve_from_container: (Symbol) -> untyped
195
+ end
196
+ end
197
+ end
@@ -36,30 +36,14 @@ module SenroUsecaser
36
36
  # end
37
37
  # end
38
38
  class Hook
39
- # Declares a dependency to be injected from the container
40
- #
41
- # : (Symbol, ?Class) -> void
42
- def self.depends_on: (Symbol, ?Class) -> void
43
-
44
- # Returns the list of declared dependencies
45
- #
46
- # : () -> Array[Symbol]
47
- def self.dependencies: () -> Array[Symbol]
48
-
49
- # Returns the dependency type mapping
50
- #
51
- # : () -> Hash[Symbol, Class]
52
- def self.dependency_types: () -> Hash[Symbol, Class]
39
+ extend DependsOn
53
40
 
54
- # Sets or returns the namespace for dependency resolution
55
- #
56
- # : (?(Symbol | String)) -> (Symbol | String)?
57
- def self.namespace: (?Symbol | String) -> (Symbol | String)?
41
+ include DependsOn::InstanceMethods
58
42
 
59
- # Alias for namespace() without arguments
43
+ # Alias for backward compatibility
60
44
  #
61
45
  # : () -> (Symbol | String)?
62
- def self.hook_namespace: () -> (Symbol | String)?
46
+ alias self.hook_namespace self.declared_namespace
63
47
 
64
48
  # @api private
65
49
  def self.inherited: (untyped subclass) -> untyped
@@ -87,26 +71,30 @@ module SenroUsecaser
87
71
  # : (untyped) { () -> Result[untyped] } -> Result[untyped]
88
72
  def around: (untyped) { () -> Result[untyped] } -> Result[untyped]
89
73
 
74
+ # Called when the UseCase fails
75
+ # Override in subclass to add failure handling or rollback logic
76
+ #
77
+ # @example Basic logging
78
+ # def on_failure(input, result)
79
+ # logger.error("Failed: #{result.errors.first&.message}")
80
+ # end
81
+ #
82
+ # @example Request retry
83
+ # def on_failure(input, result, context)
84
+ # if result.errors.first&.code == :network_error && context.attempt < 3
85
+ # context.retry!(wait: 2.0)
86
+ # end
87
+ # end
88
+ #
89
+ # : (untyped, Result[untyped], ?RetryContext?) -> void
90
+ def on_failure: (untyped, Result[untyped], ?RetryContext?) -> void
91
+
90
92
  private
91
93
 
92
94
  # Returns the effective namespace for dependency resolution
95
+ # Overrides DependsOn::InstanceMethods to add use_case_namespace fallback
93
96
  #
94
97
  # : () -> (Symbol | String)?
95
98
  def effective_namespace: () -> (Symbol | String)?
96
-
97
- # Infers namespace from the class's module structure
98
- #
99
- # : () -> String?
100
- def infer_namespace_from_class: () -> String?
101
-
102
- # Resolves dependencies from the container
103
- #
104
- # : () -> void
105
- def resolve_dependencies: () -> void
106
-
107
- # Resolves a single dependency from the container
108
- #
109
- # : (Symbol) -> untyped
110
- def resolve_from_container: (Symbol) -> untyped
111
99
  end
112
100
  end
@@ -62,7 +62,7 @@ module SenroUsecaser
62
62
  # enabled_if { Rails.env.development? }
63
63
  # end
64
64
  #
65
- # : () { () -> bool } -> void
65
+ # : () { () -> boolish } -> void
66
66
  def self.enabled_if: () { () -> boolish } -> void
67
67
 
68
68
  # Returns whether this provider is enabled
@@ -0,0 +1,90 @@
1
+ # Generated from lib/senro_usecaser/retry_configuration.rb with RBS::Inline
2
+
3
+ module SenroUsecaser
4
+ # Configuration for automatic retry behavior
5
+ #
6
+ # This class defines when and how retries should occur based on
7
+ # error codes or exception classes, with configurable backoff strategies.
8
+ #
9
+ # @example Basic retry configuration
10
+ # RetryConfiguration.new(
11
+ # matchers: [:network_error, Net::OpenTimeout],
12
+ # attempts: 3,
13
+ # wait: 1.0
14
+ # )
15
+ #
16
+ # @example With exponential backoff
17
+ # RetryConfiguration.new(
18
+ # matchers: [:rate_limited],
19
+ # attempts: 5,
20
+ # wait: 2.0,
21
+ # backoff: :exponential,
22
+ # max_wait: 60
23
+ # )
24
+ class RetryConfiguration
25
+ # Returns the list of error matchers (Symbols for error codes, Classes for exceptions)
26
+ # : () -> Array[(Symbol | Class)]
27
+ attr_reader matchers: untyped
28
+
29
+ # Returns the maximum number of attempts
30
+ # : () -> Integer
31
+ attr_reader attempts: untyped
32
+
33
+ # Returns the base wait time in seconds
34
+ # : () -> (Float | Integer)
35
+ attr_reader wait: untyped
36
+
37
+ # Returns the backoff strategy (:fixed, :linear, :exponential)
38
+ # : () -> Symbol
39
+ attr_reader backoff: untyped
40
+
41
+ # Returns the maximum wait time in seconds
42
+ # : () -> (Float | Integer)
43
+ attr_reader max_wait: untyped
44
+
45
+ # Returns the jitter factor (0.0 to 1.0)
46
+ # : () -> (Float | Integer)
47
+ attr_reader jitter: untyped
48
+
49
+ # Initializes a new retry configuration
50
+ #
51
+ # @param matchers [Array<Symbol, Class>] Error codes or exception classes to match
52
+ # @param attempts [Integer] Maximum number of attempts (default: 3)
53
+ # @param wait [Numeric] Base wait time in seconds (default: 0)
54
+ # @param backoff [Symbol] Backoff strategy: :fixed, :linear, or :exponential (default: :fixed)
55
+ # @param max_wait [Numeric] Maximum wait time in seconds (default: 3600)
56
+ # @param jitter [Numeric] Jitter factor 0.0-1.0 to randomize wait times (default: 0)
57
+ #
58
+ # rubocop:disable Metrics/ParameterLists
59
+ # : (matchers: Array[(Symbol | Class)], ?attempts: Integer, ?wait: (Float | Integer),
60
+ # : ?backoff: Symbol, ?max_wait: (Float | Integer)?, ?jitter: (Float | Integer)) -> void
61
+ def initialize: (matchers: untyped, ?attempts: untyped, ?wait: untyped, ?backoff: untyped, ?max_wait: untyped, ?jitter: untyped) -> untyped
62
+
63
+ # Checks if this configuration matches the given result
64
+ #
65
+ # : (Result[untyped]) -> bool
66
+ def matches?: (Result[untyped]) -> bool
67
+
68
+ # Calculates the wait time for the given attempt number
69
+ #
70
+ # : (Integer) -> Float
71
+ def calculate_wait: (Integer) -> Float
72
+
73
+ private
74
+
75
+ # Checks if an error matches any of the configured matchers
76
+ #
77
+ # : (Error) -> bool
78
+ def matches_error?: (Error) -> bool
79
+
80
+ # Calculates the base wait time based on backoff strategy
81
+ #
82
+ # : (Integer) -> (Float | Integer)
83
+ def calculate_base_wait: (Integer) -> (Float | Integer)
84
+
85
+ # Applies jitter to the wait time
86
+ #
87
+ # : ((Float | Integer)) -> Float
88
+ def apply_jitter: (Float | Integer) -> Float
89
+ end
90
+ end