cmdx 1.1.2 → 1.5.0
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/.DS_Store +0 -0
- data/.cursor/prompts/docs.md +4 -1
- data/.cursor/prompts/llms.md +20 -0
- data/.cursor/prompts/rspec.md +4 -1
- data/.cursor/prompts/yardoc.md +3 -2
- data/.cursor/rules/cursor-instructions.mdc +56 -1
- data/.irbrc +6 -0
- data/.rubocop.yml +29 -18
- data/CHANGELOG.md +5 -133
- data/LLM.md +3317 -0
- data/README.md +68 -44
- data/docs/attributes/coercions.md +162 -0
- data/docs/attributes/defaults.md +90 -0
- data/docs/attributes/definitions.md +281 -0
- data/docs/attributes/naming.md +78 -0
- data/docs/attributes/validations.md +309 -0
- data/docs/basics/chain.md +56 -249
- data/docs/basics/context.md +56 -289
- data/docs/basics/execution.md +114 -0
- data/docs/basics/setup.md +37 -334
- data/docs/callbacks.md +89 -467
- data/docs/deprecation.md +91 -174
- data/docs/getting_started.md +212 -202
- data/docs/internationalization.md +11 -647
- data/docs/interruptions/exceptions.md +23 -198
- data/docs/interruptions/faults.md +71 -151
- data/docs/interruptions/halt.md +109 -186
- data/docs/logging.md +44 -256
- data/docs/middlewares.md +113 -426
- data/docs/outcomes/result.md +81 -228
- data/docs/outcomes/states.md +33 -221
- data/docs/outcomes/statuses.md +21 -311
- data/docs/tips_and_tricks.md +120 -70
- data/docs/workflows.md +99 -283
- data/lib/cmdx/.DS_Store +0 -0
- data/lib/cmdx/attribute.rb +229 -0
- data/lib/cmdx/attribute_registry.rb +94 -0
- data/lib/cmdx/attribute_value.rb +193 -0
- data/lib/cmdx/callback_registry.rb +69 -77
- data/lib/cmdx/chain.rb +56 -73
- data/lib/cmdx/coercion_registry.rb +52 -68
- data/lib/cmdx/coercions/array.rb +19 -18
- data/lib/cmdx/coercions/big_decimal.rb +20 -24
- data/lib/cmdx/coercions/boolean.rb +26 -25
- data/lib/cmdx/coercions/complex.rb +21 -22
- data/lib/cmdx/coercions/date.rb +25 -23
- data/lib/cmdx/coercions/date_time.rb +24 -25
- data/lib/cmdx/coercions/float.rb +25 -22
- data/lib/cmdx/coercions/hash.rb +31 -32
- data/lib/cmdx/coercions/integer.rb +30 -24
- data/lib/cmdx/coercions/rational.rb +29 -24
- data/lib/cmdx/coercions/string.rb +19 -22
- data/lib/cmdx/coercions/symbol.rb +37 -0
- data/lib/cmdx/coercions/time.rb +26 -25
- data/lib/cmdx/configuration.rb +49 -108
- data/lib/cmdx/context.rb +222 -44
- data/lib/cmdx/deprecator.rb +61 -0
- data/lib/cmdx/errors.rb +42 -252
- data/lib/cmdx/exceptions.rb +39 -0
- data/lib/cmdx/faults.rb +78 -39
- data/lib/cmdx/freezer.rb +51 -0
- data/lib/cmdx/identifier.rb +30 -0
- data/lib/cmdx/locale.rb +52 -0
- data/lib/cmdx/log_formatters/json.rb +21 -22
- data/lib/cmdx/log_formatters/key_value.rb +20 -22
- data/lib/cmdx/log_formatters/line.rb +15 -22
- data/lib/cmdx/log_formatters/logstash.rb +22 -23
- data/lib/cmdx/log_formatters/raw.rb +16 -22
- data/lib/cmdx/middleware_registry.rb +70 -74
- data/lib/cmdx/middlewares/correlate.rb +90 -54
- data/lib/cmdx/middlewares/runtime.rb +58 -0
- data/lib/cmdx/middlewares/timeout.rb +48 -68
- data/lib/cmdx/railtie.rb +12 -45
- data/lib/cmdx/result.rb +229 -314
- data/lib/cmdx/task.rb +194 -366
- data/lib/cmdx/utils/call.rb +49 -0
- data/lib/cmdx/utils/condition.rb +71 -0
- data/lib/cmdx/utils/format.rb +61 -0
- data/lib/cmdx/validator_registry.rb +63 -72
- data/lib/cmdx/validators/exclusion.rb +38 -67
- data/lib/cmdx/validators/format.rb +48 -49
- data/lib/cmdx/validators/inclusion.rb +43 -74
- data/lib/cmdx/validators/length.rb +91 -154
- data/lib/cmdx/validators/numeric.rb +87 -162
- data/lib/cmdx/validators/presence.rb +37 -50
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx/worker.rb +178 -0
- data/lib/cmdx/workflow.rb +85 -81
- data/lib/cmdx.rb +19 -13
- data/lib/generators/cmdx/install_generator.rb +14 -13
- data/lib/generators/cmdx/task_generator.rb +25 -50
- data/lib/generators/cmdx/templates/install.rb +11 -46
- data/lib/generators/cmdx/templates/task.rb.tt +3 -2
- data/lib/locales/en.yml +18 -4
- data/src/cmdx-logo.png +0 -0
- metadata +32 -116
- data/docs/ai_prompts.md +0 -393
- data/docs/basics/call.md +0 -317
- data/docs/configuration.md +0 -344
- data/docs/parameters/coercions.md +0 -396
- data/docs/parameters/defaults.md +0 -335
- data/docs/parameters/definitions.md +0 -446
- data/docs/parameters/namespacing.md +0 -378
- data/docs/parameters/validations.md +0 -405
- data/docs/testing.md +0 -553
- data/lib/cmdx/callback.rb +0 -53
- data/lib/cmdx/chain_inspector.rb +0 -56
- data/lib/cmdx/chain_serializer.rb +0 -63
- data/lib/cmdx/coercion.rb +0 -57
- data/lib/cmdx/coercions/virtual.rb +0 -29
- data/lib/cmdx/core_ext/hash.rb +0 -83
- data/lib/cmdx/core_ext/module.rb +0 -98
- data/lib/cmdx/core_ext/object.rb +0 -125
- data/lib/cmdx/correlator.rb +0 -122
- data/lib/cmdx/error.rb +0 -67
- data/lib/cmdx/fault.rb +0 -140
- data/lib/cmdx/immutator.rb +0 -52
- data/lib/cmdx/lazy_struct.rb +0 -246
- data/lib/cmdx/log_formatters/pretty_json.rb +0 -40
- data/lib/cmdx/log_formatters/pretty_key_value.rb +0 -38
- data/lib/cmdx/log_formatters/pretty_line.rb +0 -41
- data/lib/cmdx/logger.rb +0 -49
- data/lib/cmdx/logger_ansi.rb +0 -68
- data/lib/cmdx/logger_serializer.rb +0 -116
- data/lib/cmdx/middleware.rb +0 -70
- data/lib/cmdx/parameter.rb +0 -312
- data/lib/cmdx/parameter_evaluator.rb +0 -231
- data/lib/cmdx/parameter_inspector.rb +0 -66
- data/lib/cmdx/parameter_registry.rb +0 -106
- data/lib/cmdx/parameter_serializer.rb +0 -59
- data/lib/cmdx/result_ansi.rb +0 -71
- data/lib/cmdx/result_inspector.rb +0 -71
- data/lib/cmdx/result_logger.rb +0 -59
- data/lib/cmdx/result_serializer.rb +0 -104
- data/lib/cmdx/rspec/matchers.rb +0 -28
- data/lib/cmdx/rspec/result_matchers/be_executed.rb +0 -42
- data/lib/cmdx/rspec/result_matchers/be_failed_task.rb +0 -94
- data/lib/cmdx/rspec/result_matchers/be_skipped_task.rb +0 -94
- data/lib/cmdx/rspec/result_matchers/be_state_matchers.rb +0 -59
- data/lib/cmdx/rspec/result_matchers/be_status_matchers.rb +0 -57
- data/lib/cmdx/rspec/result_matchers/be_successful_task.rb +0 -87
- data/lib/cmdx/rspec/result_matchers/have_bad_outcome.rb +0 -51
- data/lib/cmdx/rspec/result_matchers/have_caused_failure.rb +0 -58
- data/lib/cmdx/rspec/result_matchers/have_chain_index.rb +0 -59
- data/lib/cmdx/rspec/result_matchers/have_context.rb +0 -86
- data/lib/cmdx/rspec/result_matchers/have_empty_metadata.rb +0 -54
- data/lib/cmdx/rspec/result_matchers/have_good_outcome.rb +0 -52
- data/lib/cmdx/rspec/result_matchers/have_metadata.rb +0 -114
- data/lib/cmdx/rspec/result_matchers/have_preserved_context.rb +0 -66
- data/lib/cmdx/rspec/result_matchers/have_received_thrown_failure.rb +0 -64
- data/lib/cmdx/rspec/result_matchers/have_runtime.rb +0 -78
- data/lib/cmdx/rspec/result_matchers/have_thrown_failure.rb +0 -76
- data/lib/cmdx/rspec/task_matchers/be_well_formed_task.rb +0 -62
- data/lib/cmdx/rspec/task_matchers/have_callback.rb +0 -85
- data/lib/cmdx/rspec/task_matchers/have_cmd_setting.rb +0 -68
- data/lib/cmdx/rspec/task_matchers/have_executed_callbacks.rb +0 -92
- data/lib/cmdx/rspec/task_matchers/have_middleware.rb +0 -46
- data/lib/cmdx/rspec/task_matchers/have_parameter.rb +0 -181
- data/lib/cmdx/task_deprecator.rb +0 -58
- data/lib/cmdx/task_processor.rb +0 -246
- data/lib/cmdx/task_serializer.rb +0 -57
- data/lib/cmdx/utils/ansi_color.rb +0 -73
- data/lib/cmdx/utils/log_timestamp.rb +0 -36
- data/lib/cmdx/utils/monotonic_runtime.rb +0 -34
- data/lib/cmdx/utils/name_affix.rb +0 -52
- data/lib/cmdx/validator.rb +0 -57
- data/lib/generators/cmdx/templates/workflow.rb.tt +0 -7
- data/lib/generators/cmdx/workflow_generator.rb +0 -84
- data/lib/locales/ar.yml +0 -35
- data/lib/locales/cs.yml +0 -35
- data/lib/locales/da.yml +0 -35
- data/lib/locales/de.yml +0 -35
- data/lib/locales/el.yml +0 -35
- data/lib/locales/es.yml +0 -35
- data/lib/locales/fi.yml +0 -35
- data/lib/locales/fr.yml +0 -35
- data/lib/locales/he.yml +0 -35
- data/lib/locales/hi.yml +0 -35
- data/lib/locales/it.yml +0 -35
- data/lib/locales/ja.yml +0 -35
- data/lib/locales/ko.yml +0 -35
- data/lib/locales/nl.yml +0 -35
- data/lib/locales/no.yml +0 -35
- data/lib/locales/pl.yml +0 -35
- data/lib/locales/pt.yml +0 -35
- data/lib/locales/ru.yml +0 -35
- data/lib/locales/sv.yml +0 -35
- data/lib/locales/th.yml +0 -35
- data/lib/locales/tr.yml +0 -35
- data/lib/locales/vi.yml +0 -35
- data/lib/locales/zh.yml +0 -35
data/docs/basics/setup.md
CHANGED
@@ -1,375 +1,78 @@
|
|
1
1
|
# Basics - Setup
|
2
2
|
|
3
|
-
|
3
|
+
Tasks are the core building blocks of CMDx, encapsulating business logic within structured, reusable objects. Each task represents a unit of work with automatic attribute validation, error handling, and execution tracking.
|
4
4
|
|
5
5
|
## Table of Contents
|
6
6
|
|
7
|
-
- [
|
8
|
-
- [
|
9
|
-
- [
|
10
|
-
- [Inheritance and Application Tasks](#inheritance-and-application-tasks)
|
11
|
-
- [Generator](#generator)
|
12
|
-
- [Task Lifecycle](#task-lifecycle)
|
13
|
-
- [Error Handling](#error-handling)
|
7
|
+
- [Structure](#structure)
|
8
|
+
- [Inheritance](#inheritance)
|
9
|
+
- [Lifecycle](#lifecycle)
|
14
10
|
|
15
|
-
##
|
11
|
+
## Structure
|
16
12
|
|
17
|
-
|
18
|
-
# Minimal task - only call method required
|
19
|
-
class ProcessOrderTask < CMDx::Task
|
20
|
-
def call
|
21
|
-
context.result = "Order processed"
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
# Execute and access results
|
26
|
-
result = ProcessOrderTask.call(order_id: 123)
|
27
|
-
result.success? # → true
|
28
|
-
result.context.result # → "Order processed"
|
29
|
-
|
30
|
-
# With parameters and validation
|
31
|
-
class UpdateUserTask < CMDx::Task
|
32
|
-
required :user_id, type: :integer
|
33
|
-
required :email, type: :string
|
34
|
-
|
35
|
-
def call
|
36
|
-
user = User.find(context.user_id)
|
37
|
-
user.update!(email: context.email)
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
# Generator for quick scaffolding
|
42
|
-
rails g cmdx:task ProcessPayment # Creates structured template
|
43
|
-
```
|
44
|
-
|
45
|
-
## Basic Task Structure
|
46
|
-
|
47
|
-
> [!NOTE]
|
48
|
-
> Tasks are Ruby classes that inherit from `CMDx::Task`. Only the `call` method is required - all other features are optional and can be added as needed.
|
49
|
-
|
50
|
-
### Minimal Task
|
13
|
+
Tasks inherit from `CMDx::Task` and require only a `work` method:
|
51
14
|
|
52
15
|
```ruby
|
53
|
-
class
|
54
|
-
def
|
55
|
-
# Your
|
56
|
-
context.order = Order.find(context.order_id)
|
57
|
-
context.order.process!
|
16
|
+
class ValidateDocument < CMDx::Task
|
17
|
+
def work
|
18
|
+
# Your logic here...
|
58
19
|
end
|
59
20
|
end
|
60
21
|
```
|
61
22
|
|
62
|
-
|
23
|
+
An exception will be raised if a work method is not defined.
|
63
24
|
|
64
25
|
```ruby
|
65
|
-
class
|
66
|
-
#
|
67
|
-
required :amount, type: :float
|
68
|
-
required :user_id, type: :integer
|
69
|
-
optional :currency, type: :string, default: "USD"
|
70
|
-
|
71
|
-
# Callbacks (optional)
|
72
|
-
before_call :validate_user
|
73
|
-
after_call :send_notification
|
74
|
-
|
75
|
-
def call
|
76
|
-
# Core business logic
|
77
|
-
user = User.find(context.user_id)
|
78
|
-
payment = Payment.create!(
|
79
|
-
user: user,
|
80
|
-
amount: context.amount,
|
81
|
-
currency: context.currency
|
82
|
-
)
|
83
|
-
|
84
|
-
context.payment = payment
|
85
|
-
context.success_message = "Payment processed successfully"
|
86
|
-
end
|
87
|
-
|
88
|
-
private
|
89
|
-
|
90
|
-
def validate_user
|
91
|
-
# Validation logic
|
92
|
-
end
|
93
|
-
|
94
|
-
def send_notification
|
95
|
-
# Notification logic
|
96
|
-
end
|
26
|
+
class IncompleteTask < CMDx::Task
|
27
|
+
# No `work` method defined
|
97
28
|
end
|
98
|
-
```
|
99
|
-
|
100
|
-
## Task Execution
|
101
|
-
|
102
|
-
> [!IMPORTANT]
|
103
|
-
> Tasks return a `CMDx::Result` object that contains execution state, context data, and metadata. Always check the result status before accessing context data.
|
104
|
-
|
105
|
-
### Basic Execution
|
106
|
-
|
107
|
-
```ruby
|
108
|
-
# Execute a task
|
109
|
-
result = ProcessUserOrderTask.call(order_id: 123)
|
110
29
|
|
111
|
-
|
112
|
-
result.success? # → true/false
|
113
|
-
result.failed? # → true/false
|
114
|
-
|
115
|
-
# Access context data
|
116
|
-
result.context.order # → <Order id: 123>
|
117
|
-
|
118
|
-
# Access execution metadata
|
119
|
-
result.status # → :success, :failure, etc.
|
120
|
-
result.state # → :executed, :skipped, etc.
|
121
|
-
result.runtime # → 0.1234 (seconds)
|
122
|
-
```
|
123
|
-
|
124
|
-
### Handling Different Outcomes
|
125
|
-
|
126
|
-
```ruby
|
127
|
-
result = ProcessPaymentTask.call(
|
128
|
-
amount: 99.99,
|
129
|
-
user_id: 12345,
|
130
|
-
currency: "EUR"
|
131
|
-
)
|
132
|
-
|
133
|
-
case result.status
|
134
|
-
when :success
|
135
|
-
payment = result.context.payment
|
136
|
-
puts result.context.success_message
|
137
|
-
when :failure
|
138
|
-
puts "Payment failed: #{result.metadata[:reason]}"
|
139
|
-
when :halt
|
140
|
-
puts "Payment halted: #{result.metadata[:reason]}"
|
141
|
-
end
|
30
|
+
IncompleteTask.execute #=> raises CMDx::UndefinedMethodError
|
142
31
|
```
|
143
32
|
|
144
|
-
## Inheritance
|
145
|
-
|
146
|
-
> [!TIP]
|
147
|
-
> In Rails applications, create an `ApplicationTask` base class to share common configuration, middleware, and functionality across all your tasks.
|
33
|
+
## Inheritance
|
148
34
|
|
149
|
-
|
35
|
+
All configuration options are inheritable by any child classes.
|
36
|
+
Create a base class to share common configuration across tasks:
|
150
37
|
|
151
38
|
```ruby
|
152
|
-
# app/tasks/application_task.rb
|
153
39
|
class ApplicationTask < CMDx::Task
|
154
|
-
|
155
|
-
use :middleware, AuthenticateUserMiddleware
|
156
|
-
use :middleware, LogExecutionMiddleware
|
40
|
+
register :middleware, SecurityMiddleware
|
157
41
|
|
158
|
-
|
159
|
-
before_call :set_correlation_id
|
160
|
-
after_call :cleanup_temp_data
|
42
|
+
before_execution :initialize_request_tracking
|
161
43
|
|
162
|
-
|
163
|
-
optional :current_user, type: :virtual
|
164
|
-
optional :request_id, type: :string
|
44
|
+
attribute :session_id
|
165
45
|
|
166
46
|
private
|
167
47
|
|
168
|
-
def
|
169
|
-
context.
|
170
|
-
end
|
171
|
-
|
172
|
-
def cleanup_temp_data
|
173
|
-
# Cleanup logic
|
48
|
+
def initialize_request_tracking
|
49
|
+
context.tracking_id ||= SecureRandom.uuid
|
174
50
|
end
|
175
51
|
end
|
176
|
-
```
|
177
|
-
|
178
|
-
### Task Implementation
|
179
|
-
|
180
|
-
```ruby
|
181
|
-
# app/tasks/process_user_order_task.rb
|
182
|
-
class ProcessUserOrderTask < ApplicationTask
|
183
|
-
required :order_id, type: :integer
|
184
|
-
required :payment_method, type: :string
|
185
|
-
|
186
|
-
def call
|
187
|
-
# Inherits all ApplicationTask functionality
|
188
|
-
order = Order.find(context.order_id)
|
189
|
-
|
190
|
-
# Business logic specific to this task
|
191
|
-
process_order(order)
|
192
|
-
charge_payment(order, context.payment_method)
|
193
|
-
|
194
|
-
context.order = order
|
195
|
-
end
|
196
|
-
|
197
|
-
private
|
198
52
|
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
def charge_payment(order, method)
|
204
|
-
# Implementation
|
53
|
+
class SyncInventory < ApplicationTask
|
54
|
+
def work
|
55
|
+
# Your logic here...
|
205
56
|
end
|
206
57
|
end
|
207
58
|
```
|
208
59
|
|
209
|
-
##
|
60
|
+
## Lifecycle
|
210
61
|
|
211
|
-
|
212
|
-
> Rails applications can use the built-in generator to create consistent task templates with proper structure and naming conventions.
|
62
|
+
Tasks follow a predictable call pattern with specific states and statuses:
|
213
63
|
|
214
|
-
|
215
|
-
|
216
|
-
```bash
|
217
|
-
# Generate a basic task
|
218
|
-
rails g cmdx:task ProcessUserOrder
|
219
|
-
```
|
220
|
-
|
221
|
-
This creates `app/tasks/process_user_order_task.rb`:
|
222
|
-
|
223
|
-
```ruby
|
224
|
-
class ProcessUserOrderTask < ApplicationTask
|
225
|
-
# Define required parameters
|
226
|
-
# required :param_name, type: :string
|
64
|
+
> [!CAUTION]
|
65
|
+
> Tasks are single-use objects. Once executed, they are frozen and cannot be executed again.
|
227
66
|
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
private
|
237
|
-
|
238
|
-
# Add private methods for supporting logic
|
239
|
-
end
|
240
|
-
```
|
241
|
-
|
242
|
-
### Advanced Generation Options
|
243
|
-
|
244
|
-
```bash
|
245
|
-
# Generate with workflow
|
246
|
-
rails g cmdx:workflow ProcessOrder
|
247
|
-
|
248
|
-
# Generate with specific namespace
|
249
|
-
rails g cmdx:task Billing::ProcessPayment
|
250
|
-
```
|
251
|
-
|
252
|
-
## Task Lifecycle
|
253
|
-
|
254
|
-
> [!IMPORTANT]
|
255
|
-
> Understanding the task lifecycle is crucial for proper error handling and debugging. Tasks follow a predictable execution pattern with specific states and status transitions.
|
256
|
-
|
257
|
-
### Lifecycle Stages
|
258
|
-
|
259
|
-
| Stage | Description | State | Possible Statuses |
|
260
|
-
|-------|-------------|--------|-------------------|
|
261
|
-
| **Instantiation** | Task object created with context | `:initialized` | `:pending` |
|
262
|
-
| **Pre-validation** | Before callbacks and middleware run | `:executing` | `:pending` |
|
263
|
-
| **Validation** | Parameters validated against definitions | `:executing` | `:pending`, `:failure` |
|
264
|
-
| **Execution** | The `call` method runs business logic | `:executing` | `:pending`, `:halt` |
|
265
|
-
| **Post-execution** | After callbacks run | `:executing` | `:success`, `:failure` |
|
266
|
-
| **Completion** | Result finalized with final state | `:executed` | `:success`, `:failure` |
|
267
|
-
| **Freezing** | Task becomes immutable | `:executed` | Final status |
|
268
|
-
|
269
|
-
### Lifecycle Example
|
270
|
-
|
271
|
-
```ruby
|
272
|
-
class ExampleTask < CMDx::Task
|
273
|
-
required :data, type: :string
|
274
|
-
|
275
|
-
before_call :log_start
|
276
|
-
after_call :log_completion
|
277
|
-
|
278
|
-
def call
|
279
|
-
# Main logic
|
280
|
-
context.processed_data = context.data.upcase
|
281
|
-
end
|
282
|
-
|
283
|
-
private
|
284
|
-
|
285
|
-
def log_start
|
286
|
-
puts "Task starting with data: #{context.data}"
|
287
|
-
end
|
288
|
-
|
289
|
-
def log_completion
|
290
|
-
puts "Task completed: #{context.processed_data}"
|
291
|
-
end
|
292
|
-
end
|
293
|
-
|
294
|
-
# Execution trace
|
295
|
-
result = ExampleTask.call(data: "hello")
|
296
|
-
# Output:
|
297
|
-
# Task starting with data: hello
|
298
|
-
# Task completed: HELLO
|
299
|
-
|
300
|
-
result.state # → :executed
|
301
|
-
result.status # → :success
|
302
|
-
```
|
303
|
-
|
304
|
-
> [!WARNING]
|
305
|
-
> Tasks are single-use objects. Once executed, they are frozen and cannot be called again. Attempting to call a frozen task will raise an error.
|
306
|
-
|
307
|
-
```ruby
|
308
|
-
task = ProcessOrderTask.new(order_id: 123)
|
309
|
-
result1 = task.call # ✓ Works
|
310
|
-
result2 = task.call # ✗ Raises FrozenError
|
311
|
-
|
312
|
-
# Create new instances for each execution
|
313
|
-
result1 = ProcessOrderTask.call(order_id: 123)
|
314
|
-
result2 = ProcessOrderTask.call(order_id: 456) # ✓ Works
|
315
|
-
```
|
316
|
-
|
317
|
-
## Error Handling
|
318
|
-
|
319
|
-
> [!NOTE]
|
320
|
-
> CMDx provides comprehensive error handling with detailed metadata about failures, including parameter validation errors, execution exceptions, and halt conditions.
|
321
|
-
|
322
|
-
### Parameter Validation Errors
|
323
|
-
|
324
|
-
```ruby
|
325
|
-
class ProcessOrderTask < CMDx::Task
|
326
|
-
required :order_id, type: :integer
|
327
|
-
required :amount, type: :float
|
328
|
-
|
329
|
-
def call
|
330
|
-
# Task logic
|
331
|
-
end
|
332
|
-
end
|
333
|
-
|
334
|
-
# Invalid parameters
|
335
|
-
result = ProcessOrderTask.call(
|
336
|
-
order_id: "not-a-number",
|
337
|
-
amount: "invalid"
|
338
|
-
)
|
339
|
-
|
340
|
-
result.failed? # → true
|
341
|
-
result.status # → :failure
|
342
|
-
result.metadata
|
343
|
-
# {
|
344
|
-
# reason: "order_id could not coerce into an integer. amount could not coerce into a float.",
|
345
|
-
# messages: {
|
346
|
-
# order_id: ["could not coerce into an integer"],
|
347
|
-
# amount: ["could not coerce into a float"]
|
348
|
-
# }
|
349
|
-
# }
|
350
|
-
```
|
351
|
-
|
352
|
-
### Runtime Exceptions
|
353
|
-
|
354
|
-
```ruby
|
355
|
-
class ProcessOrderTask < CMDx::Task
|
356
|
-
required :order_id, type: :integer
|
357
|
-
|
358
|
-
def call
|
359
|
-
order = Order.find(context.order_id) # May raise ActiveRecord::RecordNotFound
|
360
|
-
order.process!
|
361
|
-
end
|
362
|
-
end
|
363
|
-
|
364
|
-
# Order not found
|
365
|
-
result = ProcessOrderTask.call(order_id: 99999)
|
366
|
-
|
367
|
-
result.failed? # → true
|
368
|
-
result.status # → :failure
|
369
|
-
result.metadata[:reason] # → "ActiveRecord::RecordNotFound: Couldn't find Order..."
|
370
|
-
```
|
67
|
+
| Stage | State | Status | Description |
|
68
|
+
|-------|-------|--------|-------------|
|
69
|
+
| **Instantiation** | `initialized` | `success` | Task created with context |
|
70
|
+
| **Validation** | `executing` | `success`/`failed` | Attributes validated |
|
71
|
+
| **Execution** | `executing` | `success`/`failed`/`skipped` | `work` method runs |
|
72
|
+
| **Completion** | `executed` | `success`/`failed`/`skipped` | Result finalized |
|
73
|
+
| **Freezing** | `executed` | `success`/`failed`/`skipped` | Task becomes immutable |
|
371
74
|
|
372
75
|
---
|
373
76
|
|
374
|
-
- **Prev:** [
|
375
|
-
- **Next:** [Basics -
|
77
|
+
- **Prev:** [Getting Started](../getting_started.md)
|
78
|
+
- **Next:** [Basics - Execution](execution.md)
|