cmdx 1.9.1 → 1.10.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 +4 -4
- data/.cursor/prompts/llms.md +3 -13
- data/.yardopts +7 -0
- data/CHANGELOG.md +19 -0
- data/README.md +1 -1
- data/Rakefile +21 -0
- data/docs/basics/setup.md +17 -0
- data/docs/callbacks.md +1 -1
- data/docs/configuration.md +314 -0
- data/docs/getting_started.md +37 -289
- data/docs/index.md +4 -2
- data/docs/retries.md +121 -0
- data/docs/stylesheets/extra.css +26 -26
- data/docs/tips_and_tricks.md +3 -1
- data/examples/sidekiq_async_execution.md +29 -0
- data/examples/stoplight_circuit_breaker.md +36 -0
- data/lib/cmdx/configuration.rb +15 -0
- data/lib/cmdx/executor.rb +31 -21
- data/lib/cmdx/version.rb +1 -1
- data/mkdocs.yml +66 -18
- metadata +20 -2
- data/LLM.md +0 -3674
data/lib/cmdx/configuration.rb
CHANGED
|
@@ -9,6 +9,9 @@ module CMDx
|
|
|
9
9
|
# @rbs DEFAULT_BREAKPOINTS: Array[String]
|
|
10
10
|
DEFAULT_BREAKPOINTS = %w[failed].freeze
|
|
11
11
|
|
|
12
|
+
# @rbs DEFAULT_ROLLPOINTS: Array[String]
|
|
13
|
+
DEFAULT_ROLLPOINTS = %w[failed].freeze
|
|
14
|
+
|
|
12
15
|
# Returns the middleware registry for task execution.
|
|
13
16
|
#
|
|
14
17
|
# @return [MiddlewareRegistry] The middleware registry
|
|
@@ -110,6 +113,16 @@ module CMDx
|
|
|
110
113
|
# @rbs @exception_handler: (Proc | nil)
|
|
111
114
|
attr_accessor :exception_handler
|
|
112
115
|
|
|
116
|
+
# Returns the statuses that trigger a task execution rollback.
|
|
117
|
+
#
|
|
118
|
+
# @return [Array<String>] Array of status names that trigger rollback
|
|
119
|
+
#
|
|
120
|
+
# @example
|
|
121
|
+
# config.rollback_on = ["failed", "skipped"]
|
|
122
|
+
#
|
|
123
|
+
# @rbs @rollback_on: Array[String]
|
|
124
|
+
attr_accessor :rollback_on
|
|
125
|
+
|
|
113
126
|
# Initializes a new Configuration instance with default values.
|
|
114
127
|
#
|
|
115
128
|
# Creates new registry instances for middlewares, callbacks, coercions, and
|
|
@@ -131,6 +144,7 @@ module CMDx
|
|
|
131
144
|
|
|
132
145
|
@task_breakpoints = DEFAULT_BREAKPOINTS
|
|
133
146
|
@workflow_breakpoints = DEFAULT_BREAKPOINTS
|
|
147
|
+
@rollback_on = DEFAULT_ROLLPOINTS
|
|
134
148
|
|
|
135
149
|
@backtrace = false
|
|
136
150
|
@backtrace_cleaner = nil
|
|
@@ -162,6 +176,7 @@ module CMDx
|
|
|
162
176
|
validators: @validators,
|
|
163
177
|
task_breakpoints: @task_breakpoints,
|
|
164
178
|
workflow_breakpoints: @workflow_breakpoints,
|
|
179
|
+
rollback_on: @rollback_on,
|
|
165
180
|
backtrace: @backtrace,
|
|
166
181
|
backtrace_cleaner: @backtrace_cleaner,
|
|
167
182
|
exception_handler: @exception_handler,
|
data/lib/cmdx/executor.rb
CHANGED
|
@@ -118,15 +118,12 @@ module CMDx
|
|
|
118
118
|
#
|
|
119
119
|
# @return [Boolean] Whether execution should halt
|
|
120
120
|
#
|
|
121
|
-
# @example
|
|
122
|
-
# halt_execution?(fault_exception)
|
|
123
|
-
#
|
|
124
121
|
# @rbs (Exception exception) -> bool
|
|
125
122
|
def halt_execution?(exception)
|
|
126
|
-
|
|
127
|
-
|
|
123
|
+
statuses = task.class.settings[:breakpoints] || task.class.settings[:task_breakpoints]
|
|
124
|
+
statuses = Array(statuses).map(&:to_s).uniq
|
|
128
125
|
|
|
129
|
-
|
|
126
|
+
statuses.include?(exception.result.status)
|
|
130
127
|
end
|
|
131
128
|
|
|
132
129
|
# Determines if execution should be retried based on retry configuration.
|
|
@@ -135,9 +132,6 @@ module CMDx
|
|
|
135
132
|
#
|
|
136
133
|
# @return [Boolean] Whether execution should be retried
|
|
137
134
|
#
|
|
138
|
-
# @example
|
|
139
|
-
# retry_execution?(standard_error)
|
|
140
|
-
#
|
|
141
135
|
# @rbs (Exception exception) -> bool
|
|
142
136
|
def retry_execution?(exception)
|
|
143
137
|
available_retries = (task.class.settings[:retries] || 0).to_i
|
|
@@ -157,7 +151,18 @@ module CMDx
|
|
|
157
151
|
task.to_h.merge!(reason:, remaining_retries:)
|
|
158
152
|
end
|
|
159
153
|
|
|
160
|
-
jitter = task.class.settings[:retry_jitter]
|
|
154
|
+
jitter = task.class.settings[:retry_jitter]
|
|
155
|
+
jitter =
|
|
156
|
+
if jitter.is_a?(Symbol)
|
|
157
|
+
task.send(jitter, current_retries)
|
|
158
|
+
elsif jitter.is_a?(Proc)
|
|
159
|
+
task.instance_exec(current_retries, &jitter)
|
|
160
|
+
elsif jitter.respond_to?(:call)
|
|
161
|
+
jitter.call(task, current_retries)
|
|
162
|
+
else
|
|
163
|
+
jitter.to_f * current_retries
|
|
164
|
+
end
|
|
165
|
+
|
|
161
166
|
sleep(jitter) if jitter.positive?
|
|
162
167
|
|
|
163
168
|
true
|
|
@@ -169,9 +174,6 @@ module CMDx
|
|
|
169
174
|
#
|
|
170
175
|
# @raise [Exception] The provided exception
|
|
171
176
|
#
|
|
172
|
-
# @example
|
|
173
|
-
# raise_exception(standard_error)
|
|
174
|
-
#
|
|
175
177
|
# @rbs (Exception exception) -> void
|
|
176
178
|
def raise_exception(exception)
|
|
177
179
|
Chain.clear
|
|
@@ -195,13 +197,6 @@ module CMDx
|
|
|
195
197
|
|
|
196
198
|
private
|
|
197
199
|
|
|
198
|
-
# Lazy loaded repeator instance to handle retries.
|
|
199
|
-
#
|
|
200
|
-
# @rbs () -> untyped
|
|
201
|
-
def repeator
|
|
202
|
-
@repeator ||= Repeator.new(task)
|
|
203
|
-
end
|
|
204
|
-
|
|
205
200
|
# Performs pre-execution tasks including validation and attribute verification.
|
|
206
201
|
#
|
|
207
202
|
# @rbs () -> void
|
|
@@ -244,7 +239,7 @@ module CMDx
|
|
|
244
239
|
invoke_callbacks(:on_bad) if task.result.bad?
|
|
245
240
|
end
|
|
246
241
|
|
|
247
|
-
# Finalizes execution by freezing the task and
|
|
242
|
+
# Finalizes execution by freezing the task, logging results, and rolling back work.
|
|
248
243
|
#
|
|
249
244
|
# @rbs () -> Result
|
|
250
245
|
def finalize_execution!
|
|
@@ -253,6 +248,8 @@ module CMDx
|
|
|
253
248
|
|
|
254
249
|
freeze_execution!
|
|
255
250
|
clear_chain!
|
|
251
|
+
|
|
252
|
+
rollback_execution!
|
|
256
253
|
end
|
|
257
254
|
|
|
258
255
|
# Logs the execution result at the configured log level.
|
|
@@ -309,5 +306,18 @@ module CMDx
|
|
|
309
306
|
Chain.clear
|
|
310
307
|
end
|
|
311
308
|
|
|
309
|
+
# Rolls back the work of a task.
|
|
310
|
+
#
|
|
311
|
+
# @rbs () -> void
|
|
312
|
+
def rollback_execution!
|
|
313
|
+
return unless task.respond_to?(:rollback)
|
|
314
|
+
|
|
315
|
+
statuses = task.class.settings[:rollback_on]
|
|
316
|
+
statuses = Array(statuses).map(&:to_s).uniq
|
|
317
|
+
return unless statuses.include?(task.result.status)
|
|
318
|
+
|
|
319
|
+
task.rollback
|
|
320
|
+
end
|
|
321
|
+
|
|
312
322
|
end
|
|
313
323
|
end
|
data/lib/cmdx/version.rb
CHANGED
data/mkdocs.yml
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
# yaml-language-server: $schema=https://squidfunk.github.io/mkdocs-material/schema.json
|
|
2
2
|
|
|
3
3
|
site_name: CMDx
|
|
4
|
-
|
|
5
|
-
site_description: Build business logic that's powerful, predictable, and chaos-free.
|
|
4
|
+
site_description: Build business logic that's powerful, predictable, and maintainable.
|
|
6
5
|
site_author: drexed
|
|
6
|
+
site_url: https://drexed.github.io/cmdx/
|
|
7
7
|
repo_name: drexed/cmdx
|
|
8
8
|
repo_url: https://github.com/drexed/cmdx
|
|
9
9
|
edit_uri: edit/main/docs/
|
|
@@ -43,25 +43,27 @@ theme:
|
|
|
43
43
|
icon: material/brightness-4
|
|
44
44
|
name: Switch to system preference
|
|
45
45
|
features:
|
|
46
|
+
- content.code.annotate
|
|
47
|
+
- content.code.copy
|
|
48
|
+
- content.tabs.link
|
|
49
|
+
- content.tooltips
|
|
46
50
|
- navigation.footer
|
|
47
51
|
- navigation.instant
|
|
48
52
|
- navigation.instant.prefetch
|
|
49
53
|
- navigation.instant.progress
|
|
50
|
-
- navigation.tracking
|
|
51
|
-
- navigation.sections
|
|
52
54
|
- navigation.expand
|
|
53
55
|
- navigation.path
|
|
56
|
+
- navigation.sections
|
|
54
57
|
- navigation.top
|
|
58
|
+
- navigation.tracking
|
|
59
|
+
- search.highlight
|
|
55
60
|
- search.share
|
|
56
61
|
- search.suggest
|
|
57
|
-
- search.highlight
|
|
58
|
-
- content.code.copy
|
|
59
|
-
- content.code.annotate
|
|
60
|
-
- content.tabs.link
|
|
61
|
-
- content.tooltips
|
|
62
62
|
|
|
63
63
|
markdown_extensions:
|
|
64
64
|
- admonition
|
|
65
|
+
- attr_list
|
|
66
|
+
- md_in_html
|
|
65
67
|
- pymdownx.details
|
|
66
68
|
- pymdownx.superfences
|
|
67
69
|
- pymdownx.highlight:
|
|
@@ -73,17 +75,56 @@ markdown_extensions:
|
|
|
73
75
|
- pymdownx.tabbed:
|
|
74
76
|
alternate_style: true
|
|
75
77
|
- tables
|
|
76
|
-
- attr_list
|
|
77
|
-
- md_in_html
|
|
78
78
|
- toc:
|
|
79
79
|
permalink: true
|
|
80
80
|
|
|
81
81
|
plugins:
|
|
82
82
|
- search
|
|
83
|
+
- llmstxt:
|
|
84
|
+
markdown_description: >-
|
|
85
|
+
CMDx is a Ruby framework for building maintainable, observable business logic through composable command/service objects.
|
|
86
|
+
It brings structure, consistency, and powerful developer tools to your business processes.
|
|
87
|
+
full_output: llms-full.txt
|
|
88
|
+
sections:
|
|
89
|
+
"Getting Started":
|
|
90
|
+
- index.md: CMDx framework overview, installation, quick examples, and core concepts
|
|
91
|
+
- getting_started.md: Task setup and framework fundamentals (CERO pattern)
|
|
92
|
+
- configuration.md: Comprehensive guide to CMDx configuration
|
|
93
|
+
Basics:
|
|
94
|
+
- basics/setup.md: Task structure, inheritance, and basic setup requirements
|
|
95
|
+
- basics/execution.md: Task execution methods (execute vs execute!), error handling, and control flow
|
|
96
|
+
- basics/context.md: Context object for data sharing, input/output management, and attribute access
|
|
97
|
+
- basics/chain.md: Execution chain tracking for related tasks within threads
|
|
98
|
+
Interruptions:
|
|
99
|
+
- interruptions/halt.md: Intentional task interruption using skip! and fail! methods
|
|
100
|
+
- interruptions/faults.md: Fault exceptions (SkipFault, FailFault) raised by execute! with rich context
|
|
101
|
+
- interruptions/exceptions.md: Exception handling differences between execute and execute! methods
|
|
102
|
+
Outcomes:
|
|
103
|
+
- outcomes/result.md: Result objects exposing execution state, status, context, and metadata
|
|
104
|
+
- outcomes/states.md: Execution lifecycle states (initialized, executing, complete, interrupted)
|
|
105
|
+
- outcomes/statuses.md: Business outcome statuses (success, skipped, failed) and transitions
|
|
106
|
+
Attributes:
|
|
107
|
+
- attributes/definitions.md: Attribute declarations (required/optional), validation, and type coercion
|
|
108
|
+
- attributes/naming.md: Customizing accessor method names with prefixes and suffixes
|
|
109
|
+
- attributes/coercions.md: Automatic type conversion for inputs (string to integer, date parsing, etc.)
|
|
110
|
+
- attributes/validations.md: Input validation rules (presence, length, format, numeric, inclusion, exclusion)
|
|
111
|
+
- attributes/defaults.md: Default values for optional attributes (static, dynamic, callable)
|
|
112
|
+
- attributes/transformations.md: Value transformation after coercion but before validation
|
|
113
|
+
Features:
|
|
114
|
+
- callbacks.md: Execution lifecycle callbacks (before_execution, on_success, on_failure, etc.)
|
|
115
|
+
- middlewares.md: Cross-cutting concerns wrapping task execution (authentication, caching, timeouts)
|
|
116
|
+
- logging.md: Structured logging with multiple formatters (JSON, KeyValue, Logstash, Line, Raw)
|
|
117
|
+
- internationalization.md: Multi-language support for error messages and validations (90+ locales)
|
|
118
|
+
- retries.md: Automatic retry functionality for transient failures with jitter and selective retries
|
|
119
|
+
- deprecation.md: Managing deprecated tasks with logging, warnings, or execution prevention
|
|
120
|
+
- workflows.md: Composing multiple tasks into sequential pipelines with conditional execution
|
|
121
|
+
More:
|
|
122
|
+
- tips_and_tricks.md: Best practices, patterns, and techniques for maintainable CMDx applications
|
|
83
123
|
|
|
84
124
|
nav:
|
|
85
125
|
- Home: index.md
|
|
86
126
|
- Getting Started: getting_started.md
|
|
127
|
+
- Configuration: configuration.md
|
|
87
128
|
- Basics:
|
|
88
129
|
- Setup: basics/setup.md
|
|
89
130
|
- Execution: basics/execution.md
|
|
@@ -104,13 +145,20 @@ nav:
|
|
|
104
145
|
- Validations: attributes/validations.md
|
|
105
146
|
- Defaults: attributes/defaults.md
|
|
106
147
|
- Transformations: attributes/transformations.md
|
|
107
|
-
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
148
|
+
- Features:
|
|
149
|
+
- Callbacks: callbacks.md
|
|
150
|
+
- Middlewares: middlewares.md
|
|
151
|
+
- Logging: logging.md
|
|
152
|
+
- Internationalization: internationalization.md
|
|
153
|
+
- Retries: retries.md
|
|
154
|
+
- Deprecation: deprecation.md
|
|
155
|
+
- Workflows: workflows.md
|
|
156
|
+
- More:
|
|
157
|
+
- Tips and Tricks: tips_and_tricks.md
|
|
158
|
+
- References:
|
|
159
|
+
- API YARDocs: https://drexed.github.io/cmdx/api/index.html
|
|
160
|
+
- llms.txt: https://drexed.github.io/cmdx/llms.txt
|
|
161
|
+
- llms-full.txt: https://drexed.github.io/cmdx/llms-full.txt
|
|
114
162
|
|
|
115
163
|
extra:
|
|
116
164
|
generator: false
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: cmdx
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.
|
|
4
|
+
version: 1.10.1
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Juan Gomez
|
|
@@ -191,6 +191,20 @@ dependencies:
|
|
|
191
191
|
- - ">="
|
|
192
192
|
- !ruby/object:Gem::Version
|
|
193
193
|
version: '0'
|
|
194
|
+
- !ruby/object:Gem::Dependency
|
|
195
|
+
name: yard
|
|
196
|
+
requirement: !ruby/object:Gem::Requirement
|
|
197
|
+
requirements:
|
|
198
|
+
- - ">="
|
|
199
|
+
- !ruby/object:Gem::Version
|
|
200
|
+
version: '0'
|
|
201
|
+
type: :development
|
|
202
|
+
prerelease: false
|
|
203
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
204
|
+
requirements:
|
|
205
|
+
- - ">="
|
|
206
|
+
- !ruby/object:Gem::Version
|
|
207
|
+
version: '0'
|
|
194
208
|
description: CMDx is a framework for building maintainable business processes.
|
|
195
209
|
email:
|
|
196
210
|
- drexed@users.noreply.github.com
|
|
@@ -208,10 +222,10 @@ files:
|
|
|
208
222
|
- ".rspec"
|
|
209
223
|
- ".rubocop.yml"
|
|
210
224
|
- ".ruby-version"
|
|
225
|
+
- ".yardopts"
|
|
211
226
|
- CHANGELOG.md
|
|
212
227
|
- CODE_OF_CONDUCT.md
|
|
213
228
|
- LICENSE.txt
|
|
214
|
-
- LLM.md
|
|
215
229
|
- README.md
|
|
216
230
|
- Rakefile
|
|
217
231
|
- docs/.DS_Store
|
|
@@ -228,6 +242,7 @@ files:
|
|
|
228
242
|
- docs/basics/execution.md
|
|
229
243
|
- docs/basics/setup.md
|
|
230
244
|
- docs/callbacks.md
|
|
245
|
+
- docs/configuration.md
|
|
231
246
|
- docs/deprecation.md
|
|
232
247
|
- docs/getting_started.md
|
|
233
248
|
- docs/index.md
|
|
@@ -240,11 +255,14 @@ files:
|
|
|
240
255
|
- docs/outcomes/result.md
|
|
241
256
|
- docs/outcomes/states.md
|
|
242
257
|
- docs/outcomes/statuses.md
|
|
258
|
+
- docs/retries.md
|
|
243
259
|
- docs/stylesheets/extra.css
|
|
244
260
|
- docs/tips_and_tricks.md
|
|
245
261
|
- docs/workflows.md
|
|
246
262
|
- examples/active_record_query_tagging.md
|
|
247
263
|
- examples/paper_trail_whatdunnit.md
|
|
264
|
+
- examples/sidekiq_async_execution.md
|
|
265
|
+
- examples/stoplight_circuit_breaker.md
|
|
248
266
|
- lib/cmdx.rb
|
|
249
267
|
- lib/cmdx/.DS_Store
|
|
250
268
|
- lib/cmdx/attribute.rb
|