cmdx 1.1.0 → 1.1.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/docs.md +9 -0
- data/.cursor/prompts/rspec.md +13 -12
- data/.cursor/prompts/yardoc.md +11 -6
- data/CHANGELOG.md +13 -2
- data/README.md +1 -0
- data/docs/ai_prompts.md +269 -195
- data/docs/basics/call.md +124 -58
- data/docs/basics/chain.md +190 -160
- data/docs/basics/context.md +242 -154
- data/docs/basics/setup.md +302 -32
- data/docs/callbacks.md +390 -94
- data/docs/configuration.md +181 -65
- data/docs/deprecation.md +245 -0
- data/docs/getting_started.md +161 -39
- data/docs/internationalization.md +590 -70
- data/docs/interruptions/exceptions.md +135 -118
- data/docs/interruptions/faults.md +150 -125
- data/docs/interruptions/halt.md +134 -80
- data/docs/logging.md +181 -118
- data/docs/middlewares.md +150 -377
- data/docs/outcomes/result.md +140 -112
- data/docs/outcomes/states.md +134 -99
- data/docs/outcomes/statuses.md +204 -146
- data/docs/parameters/coercions.md +232 -281
- data/docs/parameters/defaults.md +224 -169
- data/docs/parameters/definitions.md +289 -141
- data/docs/parameters/namespacing.md +250 -161
- data/docs/parameters/validations.md +260 -133
- data/docs/testing.md +191 -197
- data/docs/workflows.md +143 -98
- data/lib/cmdx/callback.rb +23 -19
- data/lib/cmdx/callback_registry.rb +1 -3
- data/lib/cmdx/chain_inspector.rb +23 -23
- data/lib/cmdx/chain_serializer.rb +38 -19
- data/lib/cmdx/coercion.rb +20 -12
- data/lib/cmdx/coercion_registry.rb +51 -32
- data/lib/cmdx/configuration.rb +84 -31
- data/lib/cmdx/context.rb +32 -21
- data/lib/cmdx/core_ext/hash.rb +13 -13
- data/lib/cmdx/core_ext/module.rb +1 -1
- data/lib/cmdx/core_ext/object.rb +12 -12
- data/lib/cmdx/correlator.rb +60 -39
- data/lib/cmdx/errors.rb +105 -131
- data/lib/cmdx/fault.rb +66 -45
- data/lib/cmdx/immutator.rb +20 -21
- data/lib/cmdx/lazy_struct.rb +78 -70
- data/lib/cmdx/log_formatters/json.rb +1 -1
- data/lib/cmdx/log_formatters/key_value.rb +1 -1
- data/lib/cmdx/log_formatters/line.rb +1 -1
- data/lib/cmdx/log_formatters/logstash.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_json.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_key_value.rb +1 -1
- data/lib/cmdx/log_formatters/pretty_line.rb +1 -1
- data/lib/cmdx/log_formatters/raw.rb +2 -2
- data/lib/cmdx/logger.rb +19 -14
- data/lib/cmdx/logger_ansi.rb +33 -17
- data/lib/cmdx/logger_serializer.rb +85 -24
- data/lib/cmdx/middleware.rb +39 -21
- data/lib/cmdx/middleware_registry.rb +4 -3
- data/lib/cmdx/parameter.rb +151 -89
- data/lib/cmdx/parameter_inspector.rb +34 -21
- data/lib/cmdx/parameter_registry.rb +36 -30
- data/lib/cmdx/parameter_serializer.rb +21 -14
- data/lib/cmdx/result.rb +136 -135
- data/lib/cmdx/result_ansi.rb +31 -17
- data/lib/cmdx/result_inspector.rb +32 -27
- data/lib/cmdx/result_logger.rb +23 -14
- data/lib/cmdx/result_serializer.rb +65 -27
- data/lib/cmdx/task.rb +234 -113
- data/lib/cmdx/task_deprecator.rb +22 -25
- data/lib/cmdx/task_processor.rb +89 -88
- data/lib/cmdx/task_serializer.rb +27 -14
- data/lib/cmdx/utils/monotonic_runtime.rb +2 -4
- data/lib/cmdx/validator.rb +25 -16
- data/lib/cmdx/validator_registry.rb +53 -31
- data/lib/cmdx/validators/exclusion.rb +1 -1
- data/lib/cmdx/validators/format.rb +2 -2
- data/lib/cmdx/validators/inclusion.rb +2 -2
- data/lib/cmdx/validators/length.rb +2 -2
- data/lib/cmdx/validators/numeric.rb +3 -3
- data/lib/cmdx/validators/presence.rb +2 -2
- data/lib/cmdx/version.rb +1 -1
- data/lib/cmdx/workflow.rb +54 -33
- data/lib/generators/cmdx/task_generator.rb +6 -6
- data/lib/generators/cmdx/workflow_generator.rb +6 -6
- metadata +3 -1
data/docs/configuration.md
CHANGED
@@ -18,15 +18,31 @@ CMDx provides a flexible configuration system that allows customization at both
|
|
18
18
|
- [Configuration Management](#configuration-management)
|
19
19
|
- [Accessing Configuration](#accessing-configuration)
|
20
20
|
- [Resetting Configuration](#resetting-configuration)
|
21
|
+
- [Error Handling](#error-handling)
|
21
22
|
|
22
23
|
## TLDR
|
23
24
|
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
25
|
+
```ruby
|
26
|
+
# Generate configuration file
|
27
|
+
rails g cmdx:install
|
28
|
+
|
29
|
+
# Global configuration
|
30
|
+
CMDx.configure do |config|
|
31
|
+
config.task_halt = ["failed", "skipped"] # Multiple halt statuses
|
32
|
+
config.logger = Rails.logger # Custom logger
|
33
|
+
config.middlewares.use TimeoutMiddleware # Global middleware
|
34
|
+
config.callbacks.register :on_failure, :log # Global callback
|
35
|
+
end
|
36
|
+
|
37
|
+
# Task-level overrides
|
38
|
+
class PaymentTask < CMDx::Task
|
39
|
+
cmd_settings!(task_halt: "failed", tags: ["payments"])
|
40
|
+
|
41
|
+
def call
|
42
|
+
halt_on = cmd_setting(:task_halt) # Access settings
|
43
|
+
end
|
44
|
+
end
|
45
|
+
```
|
30
46
|
|
31
47
|
## Configuration Hierarchy
|
32
48
|
|
@@ -47,7 +63,7 @@ Generate a configuration file using the Rails generator:
|
|
47
63
|
rails g cmdx:install
|
48
64
|
```
|
49
65
|
|
50
|
-
This creates `config/initializers/cmdx.rb` with
|
66
|
+
This creates `config/initializers/cmdx.rb` with sensible defaults.
|
51
67
|
|
52
68
|
### Configuration Options
|
53
69
|
|
@@ -63,102 +79,112 @@ This creates `config/initializers/cmdx.rb` with default settings.
|
|
63
79
|
|
64
80
|
### Global Middlewares
|
65
81
|
|
66
|
-
Configure middlewares that automatically apply to all tasks
|
82
|
+
Configure middlewares that automatically apply to all tasks:
|
67
83
|
|
68
84
|
```ruby
|
69
85
|
CMDx.configure do |config|
|
70
|
-
#
|
86
|
+
# Simple middleware registration
|
71
87
|
config.middlewares.use CMDx::Middlewares::Timeout
|
72
88
|
|
73
|
-
#
|
89
|
+
# Middleware with configuration
|
74
90
|
config.middlewares.use CMDx::Middlewares::Timeout, seconds: 30
|
75
91
|
|
76
|
-
#
|
77
|
-
config.middlewares.use
|
92
|
+
# Multiple middlewares
|
93
|
+
config.middlewares.use AuthenticationMiddleware
|
94
|
+
config.middlewares.use LoggingMiddleware, level: :debug
|
95
|
+
config.middlewares.use MetricsMiddleware, namespace: "app.tasks"
|
78
96
|
end
|
79
97
|
```
|
80
98
|
|
99
|
+
> [!NOTE]
|
100
|
+
> Middlewares are executed in registration order. Each middleware wraps the next, creating an execution chain around task logic.
|
101
|
+
|
81
102
|
### Global Callbacks
|
82
103
|
|
83
|
-
Configure callbacks that automatically apply to all tasks
|
104
|
+
Configure callbacks that automatically apply to all tasks:
|
84
105
|
|
85
106
|
```ruby
|
86
107
|
CMDx.configure do |config|
|
87
|
-
#
|
88
|
-
config.callbacks.register :before_execution, :
|
89
|
-
|
90
|
-
# Add callback instances
|
91
|
-
config.callbacks.register :on_success, NotificationCallback.new([:slack])
|
108
|
+
# Method callbacks
|
109
|
+
config.callbacks.register :before_execution, :setup_request_context
|
110
|
+
config.callbacks.register :after_execution, :cleanup_temp_files
|
92
111
|
|
93
|
-
#
|
94
|
-
config.callbacks.register :on_failure, :
|
112
|
+
# Conditional callbacks
|
113
|
+
config.callbacks.register :on_failure, :notify_admin, if: :production?
|
114
|
+
config.callbacks.register :on_success, :update_metrics, unless: :test?
|
95
115
|
|
96
|
-
#
|
116
|
+
# Proc callbacks with context
|
97
117
|
config.callbacks.register :on_complete, proc { |task, type|
|
98
|
-
|
118
|
+
duration = task.metadata[:runtime]
|
119
|
+
StatsD.histogram("task.duration", duration, tags: ["class:#{task.class.name}"])
|
99
120
|
}
|
100
121
|
end
|
101
122
|
```
|
102
123
|
|
103
124
|
### Global Coercions
|
104
125
|
|
105
|
-
Configure custom coercions
|
126
|
+
Configure custom coercions for domain-specific types:
|
106
127
|
|
107
128
|
```ruby
|
108
129
|
CMDx.configure do |config|
|
109
|
-
#
|
130
|
+
# Simple coercion classes
|
110
131
|
config.coercions.register :money, MoneyCoercion
|
132
|
+
config.coercions.register :email, EmailCoercion
|
111
133
|
|
112
|
-
#
|
113
|
-
config.coercions.register :
|
134
|
+
# Complex coercions with options
|
135
|
+
config.coercions.register :csv_array, proc { |value, options|
|
114
136
|
separator = options[:separator] || ','
|
115
|
-
|
137
|
+
max_items = options[:max_items] || 100
|
116
138
|
|
117
|
-
|
118
|
-
|
119
|
-
tags.uniq
|
139
|
+
items = value.to_s.split(separator).map(&:strip).reject(&:empty?)
|
140
|
+
items.first(max_items)
|
120
141
|
}
|
121
142
|
end
|
122
143
|
```
|
123
144
|
|
124
145
|
### Global Validators
|
125
146
|
|
126
|
-
Configure validators
|
147
|
+
Configure custom validators for parameter validation:
|
127
148
|
|
128
149
|
```ruby
|
129
150
|
CMDx.configure do |config|
|
130
|
-
#
|
151
|
+
# Validator classes
|
131
152
|
config.validators.register :email, EmailValidator
|
153
|
+
config.validators.register :phone, PhoneValidator
|
132
154
|
|
133
|
-
#
|
134
|
-
config.validators.register :
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
else
|
140
|
-
value.match?(/\A\+?\d{10,15}\z/)
|
141
|
-
end
|
155
|
+
# Proc validators with options
|
156
|
+
config.validators.register :api_key, proc { |value, options|
|
157
|
+
required_prefix = options.dig(:api_key, :prefix) || "sk_"
|
158
|
+
min_length = options.dig(:api_key, :min_length) || 32
|
159
|
+
|
160
|
+
value.start_with?(required_prefix) && value.length >= min_length
|
142
161
|
}
|
143
162
|
end
|
144
163
|
```
|
145
164
|
|
146
165
|
## Task Settings
|
147
166
|
|
148
|
-
Override global configuration for specific tasks
|
167
|
+
Override global configuration for specific tasks using `cmd_settings!`:
|
149
168
|
|
150
169
|
```ruby
|
151
170
|
class ProcessPaymentTask < CMDx::Task
|
152
171
|
cmd_settings!(
|
153
|
-
task_halt: ["failed"],
|
154
|
-
tags: ["payments", "critical"],
|
155
|
-
logger:
|
156
|
-
log_level: :info,
|
157
|
-
log_formatter: CMDx::LogFormatters::Json.new
|
172
|
+
task_halt: ["failed"], # Only halt on failures
|
173
|
+
tags: ["payments", "critical"], # Logging tags
|
174
|
+
logger: PaymentLogger.new, # Custom logger
|
175
|
+
log_level: :info, # Log level override
|
176
|
+
log_formatter: CMDx::LogFormatters::Json.new # JSON formatting
|
158
177
|
)
|
159
178
|
|
160
179
|
def call
|
161
|
-
#
|
180
|
+
# Payment processing logic
|
181
|
+
charge_customer(amount, payment_method)
|
182
|
+
end
|
183
|
+
|
184
|
+
private
|
185
|
+
|
186
|
+
def charge_customer(amount, method)
|
187
|
+
# Implementation details
|
162
188
|
end
|
163
189
|
end
|
164
190
|
```
|
@@ -174,18 +200,39 @@ end
|
|
174
200
|
| `log_level` | Symbol | Log level (`:debug`, `:info`, `:warn`, `:error`, `:fatal`) |
|
175
201
|
| `log_formatter` | LogFormatter | Custom log formatter |
|
176
202
|
|
203
|
+
> [!TIP]
|
204
|
+
> Use task-level settings for tasks that require special handling, such as payment processing, external API calls, or critical system operations.
|
205
|
+
|
177
206
|
### Workflow Configuration
|
178
207
|
|
179
|
-
Configure halt behavior for workflows:
|
208
|
+
Configure halt behavior and logging for workflows:
|
180
209
|
|
181
210
|
```ruby
|
182
211
|
class OrderProcessingWorkflow < CMDx::Workflow
|
183
|
-
#
|
184
|
-
cmd_settings!(
|
212
|
+
# Halt on any non-success status
|
213
|
+
cmd_settings!(
|
214
|
+
workflow_halt: ["failed", "skipped"],
|
215
|
+
tags: ["orders", "e-commerce"],
|
216
|
+
log_level: :info
|
217
|
+
)
|
185
218
|
|
186
219
|
process ValidateOrderTask
|
187
220
|
process ChargePaymentTask
|
188
|
-
process
|
221
|
+
process UpdateInventoryTask
|
222
|
+
process SendConfirmationTask
|
223
|
+
end
|
224
|
+
|
225
|
+
class DataMigrationWorkflow < CMDx::Workflow
|
226
|
+
# Continue on skipped tasks, halt only on failures
|
227
|
+
cmd_settings!(
|
228
|
+
workflow_halt: "failed",
|
229
|
+
tags: ["migration", "maintenance"]
|
230
|
+
)
|
231
|
+
|
232
|
+
process BackupDataTask
|
233
|
+
process MigrateUsersTask
|
234
|
+
process MigrateOrdersTask
|
235
|
+
process ValidateDataTask
|
189
236
|
end
|
190
237
|
```
|
191
238
|
|
@@ -194,34 +241,103 @@ end
|
|
194
241
|
### Accessing Configuration
|
195
242
|
|
196
243
|
```ruby
|
197
|
-
# Global configuration
|
198
|
-
CMDx.configuration.logger
|
199
|
-
CMDx.configuration.task_halt
|
200
|
-
CMDx.configuration.middlewares
|
201
|
-
CMDx.configuration.callbacks
|
202
|
-
CMDx.configuration.coercions #=> <CoercionRegistry instance>
|
203
|
-
CMDx.configuration.validators #=> <ValidatorRegistry instance>
|
244
|
+
# Global configuration access
|
245
|
+
CMDx.configuration.logger #=> <Logger instance>
|
246
|
+
CMDx.configuration.task_halt #=> "failed"
|
247
|
+
CMDx.configuration.middlewares.middlewares #=> [<Middleware>, ...]
|
248
|
+
CMDx.configuration.callbacks.callbacks #=> {before_execution: [...], ...}
|
204
249
|
|
205
250
|
# Task-specific settings
|
206
|
-
class
|
207
|
-
cmd_settings!(
|
251
|
+
class DataProcessingTask < CMDx::Task
|
252
|
+
cmd_settings!(
|
253
|
+
tags: ["data", "analytics"],
|
254
|
+
task_halt: ["failed", "skipped"]
|
255
|
+
)
|
208
256
|
|
209
257
|
def call
|
210
|
-
|
211
|
-
|
258
|
+
# Access current task settings
|
259
|
+
log_tags = cmd_setting(:tags) #=> ["data", "analytics"]
|
260
|
+
halt_on = cmd_setting(:task_halt) #=> ["failed", "skipped"]
|
261
|
+
logger_instance = cmd_setting(:logger) #=> Inherited from global
|
212
262
|
end
|
213
263
|
end
|
214
264
|
```
|
215
265
|
|
216
266
|
### Resetting Configuration
|
217
267
|
|
218
|
-
|
268
|
+
> [!WARNING]
|
269
|
+
> Resetting configuration affects the entire application. Use primarily in test environments or during application initialization.
|
219
270
|
|
220
271
|
```ruby
|
272
|
+
# Reset to framework defaults
|
221
273
|
CMDx.reset_configuration!
|
222
|
-
|
274
|
+
|
275
|
+
# Verify reset
|
276
|
+
CMDx.configuration.task_halt #=> "failed" (default)
|
277
|
+
CMDx.configuration.middlewares #=> Empty registry
|
278
|
+
CMDx.configuration.callbacks #=> Empty registry
|
279
|
+
|
280
|
+
# Commonly used in test setup
|
281
|
+
RSpec.configure do |config|
|
282
|
+
config.before(:each) do
|
283
|
+
CMDx.reset_configuration!
|
284
|
+
end
|
285
|
+
end
|
286
|
+
```
|
287
|
+
|
288
|
+
## Error Handling
|
289
|
+
|
290
|
+
### Configuration Validation
|
291
|
+
|
292
|
+
```ruby
|
293
|
+
# Invalid configuration types
|
294
|
+
CMDx.configure do |config|
|
295
|
+
config.task_halt = :invalid_type # Error: must be String or Array
|
296
|
+
config.logger = "not_a_logger" # Error: must respond to logging methods
|
297
|
+
end
|
298
|
+
```
|
299
|
+
|
300
|
+
### Missing Settings Access
|
301
|
+
|
302
|
+
```ruby
|
303
|
+
class ExampleTask < CMDx::Task
|
304
|
+
def call
|
305
|
+
# Accessing non-existent setting
|
306
|
+
value = cmd_setting(:non_existent_setting) #=> nil (returns nil for undefined)
|
307
|
+
|
308
|
+
# Check if setting exists
|
309
|
+
if cmd_setting(:custom_timeout)
|
310
|
+
timeout = cmd_setting(:custom_timeout)
|
311
|
+
else
|
312
|
+
timeout = 30 # fallback
|
313
|
+
end
|
314
|
+
end
|
315
|
+
end
|
316
|
+
```
|
317
|
+
|
318
|
+
### Configuration Conflicts
|
319
|
+
|
320
|
+
```ruby
|
321
|
+
# Parent class configuration
|
322
|
+
class BaseTask < CMDx::Task
|
323
|
+
cmd_settings!(task_halt: "failed", tags: ["base"])
|
324
|
+
end
|
325
|
+
|
326
|
+
# Child class inherits and overrides
|
327
|
+
class SpecialTask < BaseTask
|
328
|
+
cmd_settings!(task_halt: ["failed", "skipped"]) # Overrides parent
|
329
|
+
# tags: ["base"] inherited from parent
|
330
|
+
|
331
|
+
def call
|
332
|
+
halt_statuses = cmd_setting(:task_halt) #=> ["failed", "skipped"]
|
333
|
+
inherited_tags = cmd_setting(:tags) #=> ["base"]
|
334
|
+
end
|
335
|
+
end
|
223
336
|
```
|
224
337
|
|
338
|
+
> [!IMPORTANT]
|
339
|
+
> Settings inheritance follows Ruby's method resolution order. Child class settings always override parent class settings for the same key.
|
340
|
+
|
225
341
|
---
|
226
342
|
|
227
343
|
- **Prev:** [Getting Started](getting_started.md)
|
data/docs/deprecation.md
ADDED
@@ -0,0 +1,245 @@
|
|
1
|
+
# Task Deprecation
|
2
|
+
|
3
|
+
Task deprecation provides a systematic approach to managing legacy tasks in CMDx applications. The deprecation system enables controlled migration paths by issuing warnings, logging messages, or preventing execution of deprecated tasks entirely, helping teams maintain code quality while providing clear upgrade paths.
|
4
|
+
|
5
|
+
## Table of Contents
|
6
|
+
|
7
|
+
- [TLDR](#tldr)
|
8
|
+
- [Deprecation Fundamentals](#deprecation-fundamentals)
|
9
|
+
- [Deprecation Modes](#deprecation-modes)
|
10
|
+
- [Configuration Examples](#configuration-examples)
|
11
|
+
- [Migration Strategies](#migration-strategies)
|
12
|
+
- [Error Handling](#error-handling)
|
13
|
+
- [Best Practices](#best-practices)
|
14
|
+
|
15
|
+
## TLDR
|
16
|
+
|
17
|
+
```ruby
|
18
|
+
# Prevent task execution completely
|
19
|
+
class LegacyTask < CMDx::Task
|
20
|
+
cmd_setting!(deprecated: :error)
|
21
|
+
end
|
22
|
+
|
23
|
+
# Log deprecation warnings
|
24
|
+
class OldTask < CMDx::Task
|
25
|
+
cmd_setting!(deprecated: :log)
|
26
|
+
end
|
27
|
+
|
28
|
+
# Issue Ruby warnings
|
29
|
+
class ObsoleteTask < CMDx::Task
|
30
|
+
cmd_setting!(deprecated: :warning)
|
31
|
+
end
|
32
|
+
|
33
|
+
# Usage triggers appropriate deprecation handling
|
34
|
+
LegacyTask.call # → raises DeprecationError
|
35
|
+
OldTask.call # → logs warning via task.logger
|
36
|
+
ObsoleteTask.call # → issues Ruby warning
|
37
|
+
```
|
38
|
+
|
39
|
+
## Deprecation Fundamentals
|
40
|
+
|
41
|
+
> [!NOTE]
|
42
|
+
> Task deprecation is configured using the `cmd_setting!` declaration and processed automatically by CMDx before task execution. The deprecation system integrates seamlessly with existing logging and error handling infrastructure.
|
43
|
+
|
44
|
+
### How It Works
|
45
|
+
|
46
|
+
1. **Configuration**: Tasks declare deprecation mode using `cmd_setting!(deprecated: mode)`
|
47
|
+
2. **Processing**: CMDx automatically calls `TaskDeprecator.call(task)` during task lifecycle
|
48
|
+
3. **Action**: Appropriate deprecation handling occurs based on configured mode
|
49
|
+
4. **Execution**: Task proceeds normally (unless `:error` mode prevents it)
|
50
|
+
|
51
|
+
### Available Modes
|
52
|
+
|
53
|
+
| Mode | Behavior | Use Case |
|
54
|
+
|------|----------|----------|
|
55
|
+
| `:error` | Raises `DeprecationError` | Hard deprecation, prevent execution |
|
56
|
+
| `:log` | Logs warning via `task.logger.warn` | Soft deprecation, track usage |
|
57
|
+
| `:warning` | Issues Ruby warning | Development alerts |
|
58
|
+
| `true` | Same as `:log` | Legacy boolean support |
|
59
|
+
| `nil/false` | No deprecation handling | Default behavior |
|
60
|
+
|
61
|
+
## Deprecation Modes
|
62
|
+
|
63
|
+
### Error Mode (Hard Deprecation)
|
64
|
+
|
65
|
+
> [!WARNING]
|
66
|
+
> Error mode prevents task execution entirely. Use this for tasks that should no longer be used under any circumstances.
|
67
|
+
|
68
|
+
```ruby
|
69
|
+
class ProcessLegacyPaymentTask < CMDx::Task
|
70
|
+
cmd_setting!(deprecated: :error)
|
71
|
+
|
72
|
+
def call
|
73
|
+
# This code will never execute
|
74
|
+
charge_customer(amount)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Attempting to use deprecated task
|
79
|
+
result = ProcessLegacyPaymentTask.call(amount: 100)
|
80
|
+
# → raises CMDx::DeprecationError: "ProcessLegacyPaymentTask usage prohibited"
|
81
|
+
```
|
82
|
+
|
83
|
+
### Log Mode (Soft Deprecation)
|
84
|
+
|
85
|
+
> [!TIP]
|
86
|
+
> Log mode allows continued usage while tracking deprecation warnings. Perfect for gradual migration scenarios where immediate replacement isn't feasible.
|
87
|
+
|
88
|
+
```ruby
|
89
|
+
class ProcessOldPaymentTask < CMDx::Task
|
90
|
+
cmd_setting!(deprecated: :log)
|
91
|
+
|
92
|
+
def call
|
93
|
+
# Task executes normally but logs deprecation warning
|
94
|
+
charge_customer(amount)
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Task executes with logged warning
|
99
|
+
result = ProcessOldPaymentTask.call(amount: 100)
|
100
|
+
result.successful? # → true
|
101
|
+
|
102
|
+
# Check logs for deprecation warning:
|
103
|
+
# WARN -- : DEPRECATED: migrate to replacement or discontinue use
|
104
|
+
```
|
105
|
+
|
106
|
+
### Warning Mode (Development Alerts)
|
107
|
+
|
108
|
+
> [!NOTE]
|
109
|
+
> Warning mode issues Ruby warnings visible in development and testing environments. Useful for alerting developers without affecting production logging.
|
110
|
+
|
111
|
+
```ruby
|
112
|
+
class ProcessObsoletePaymentTask < CMDx::Task
|
113
|
+
cmd_setting!(deprecated: :warning)
|
114
|
+
|
115
|
+
def call
|
116
|
+
# Task executes with Ruby warning
|
117
|
+
charge_customer(amount)
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
# Task executes with Ruby warning
|
122
|
+
result = ProcessObsoletePaymentTask.call(amount: 100)
|
123
|
+
# stderr: [ProcessObsoletePaymentTask] DEPRECATED: migrate to replacement or discontinue use
|
124
|
+
|
125
|
+
result.successful? # → true
|
126
|
+
```
|
127
|
+
|
128
|
+
## Configuration Examples
|
129
|
+
|
130
|
+
### Environment-Specific Deprecation
|
131
|
+
|
132
|
+
```ruby
|
133
|
+
class ExperimentalFeatureTask < CMDx::Task
|
134
|
+
# Different deprecation behavior per environment
|
135
|
+
cmd_setting!(
|
136
|
+
deprecated: Rails.env.production? ? :error : :warning
|
137
|
+
)
|
138
|
+
|
139
|
+
def call
|
140
|
+
enable_experimental_feature
|
141
|
+
end
|
142
|
+
end
|
143
|
+
```
|
144
|
+
|
145
|
+
### Conditional Deprecation
|
146
|
+
|
147
|
+
```ruby
|
148
|
+
class LegacyIntegrationTask < CMDx::Task
|
149
|
+
# Deprecate only for specific conditions
|
150
|
+
cmd_setting!(
|
151
|
+
deprecated: -> { ENV['NEW_API_ENABLED'] == 'true' ? :log : nil }
|
152
|
+
)
|
153
|
+
|
154
|
+
def call
|
155
|
+
call_legacy_api
|
156
|
+
end
|
157
|
+
end
|
158
|
+
```
|
159
|
+
|
160
|
+
## Migration Strategies
|
161
|
+
|
162
|
+
> [!IMPORTANT]
|
163
|
+
> When deprecating tasks, always provide clear migration paths and replacement implementations to minimize disruption.
|
164
|
+
|
165
|
+
### Graceful Fallback
|
166
|
+
|
167
|
+
```ruby
|
168
|
+
class NotificationTask < CMDx::Task
|
169
|
+
cmd_setting!(deprecated: :log)
|
170
|
+
|
171
|
+
def call
|
172
|
+
# Provide fallback while encouraging migration
|
173
|
+
logger.warn "Consider migrating to NotificationServiceV2"
|
174
|
+
|
175
|
+
# Delegate to new service but maintain compatibility
|
176
|
+
NotificationServiceV2.send_notification(
|
177
|
+
recipient: recipient,
|
178
|
+
message: message,
|
179
|
+
delivery_method: :legacy
|
180
|
+
)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
```
|
184
|
+
|
185
|
+
## Error Handling
|
186
|
+
|
187
|
+
### Catching Deprecation Errors
|
188
|
+
|
189
|
+
```ruby
|
190
|
+
begin
|
191
|
+
result = LegacyTask.call(params)
|
192
|
+
rescue CMDx::DeprecationError => e
|
193
|
+
# Handle deprecation gracefully
|
194
|
+
Rails.logger.error "Attempted to use deprecated task: #{e.message}"
|
195
|
+
|
196
|
+
# Use replacement task instead
|
197
|
+
result = ReplacementTask.call(params)
|
198
|
+
end
|
199
|
+
|
200
|
+
if result.successful?
|
201
|
+
# Process successful result
|
202
|
+
else
|
203
|
+
# Handle task failure
|
204
|
+
end
|
205
|
+
```
|
206
|
+
|
207
|
+
## Best Practices
|
208
|
+
|
209
|
+
### Documentation and Communication
|
210
|
+
|
211
|
+
> [!TIP]
|
212
|
+
> Always document deprecation reasons, timelines, and migration paths. Clear communication prevents confusion and reduces support burden.
|
213
|
+
|
214
|
+
```ruby
|
215
|
+
class LegacyReportTask < CMDx::Task
|
216
|
+
# Document deprecation clearly
|
217
|
+
cmd_setting!(deprecated: :log)
|
218
|
+
|
219
|
+
# Class-level documentation
|
220
|
+
# @deprecated Use ReportGeneratorV2Task instead
|
221
|
+
# @see ReportGeneratorV2Task
|
222
|
+
# @note This task will be removed in v2.0.0
|
223
|
+
# @since 1.5.0 marked as deprecated
|
224
|
+
|
225
|
+
def call
|
226
|
+
# Add inline documentation
|
227
|
+
logger.warn <<~DEPRECATION
|
228
|
+
LegacyReportTask is deprecated and will be removed in v2.0.0.
|
229
|
+
Please migrate to ReportGeneratorV2Task which provides:
|
230
|
+
- Better performance
|
231
|
+
- Enhanced error handling
|
232
|
+
- More flexible output formats
|
233
|
+
|
234
|
+
Migration guide: https://docs.example.com/migration/reports
|
235
|
+
DEPRECATION
|
236
|
+
|
237
|
+
generate_legacy_report
|
238
|
+
end
|
239
|
+
end
|
240
|
+
```
|
241
|
+
|
242
|
+
---
|
243
|
+
|
244
|
+
- **Prev:** [Testing](testing.md)
|
245
|
+
- **Next:** [AI Prompts](ai_prompts.md)
|