cmdx 1.9.1 → 1.10.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/.cursor/prompts/llms.md +3 -13
- data/CHANGELOG.md +10 -0
- data/LLM.md +429 -376
- data/README.md +1 -1
- data/docs/basics/setup.md +17 -0
- data/docs/callbacks.md +1 -1
- data/docs/getting_started.md +13 -2
- data/docs/retries.md +121 -0
- data/docs/tips_and_tricks.md +2 -1
- data/examples/stoplight_circuit_breaker.md +36 -0
- data/lib/cmdx/configuration.rb +15 -0
- data/lib/cmdx/executor.rb +31 -14
- data/lib/cmdx/version.rb +1 -1
- data/mkdocs.yml +3 -1
- metadata +3 -1
    
        data/README.md
    CHANGED
    
    | @@ -6,7 +6,7 @@ | |
| 6 6 |  | 
| 7 7 | 
             
              Build business logic that’s powerful, predictable, and maintainable.
         | 
| 8 8 |  | 
| 9 | 
            -
              [Documentation](https://drexed.github.io/cmdx) · [Changelog](./CHANGELOG.md) · [Report Bug](https://github.com/drexed/cmdx/issues) · [Request Feature](https://github.com/drexed/cmdx/issues)
         | 
| 9 | 
            +
              [Documentation](https://drexed.github.io/cmdx) · [Changelog](./CHANGELOG.md) · [Report Bug](https://github.com/drexed/cmdx/issues) · [Request Feature](https://github.com/drexed/cmdx/issues) · [LLM.md](https://raw.githubusercontent.com/drexed/cmdx/refs/heads/main/LLM.md)
         | 
| 10 10 |  | 
| 11 11 | 
             
              <img alt="Version" src="https://img.shields.io/gem/v/cmdx">
         | 
| 12 12 | 
             
              <img alt="Build" src="https://github.com/drexed/cmdx/actions/workflows/ci.yml/badge.svg">
         | 
    
        data/docs/basics/setup.md
    CHANGED
    
    | @@ -24,6 +24,22 @@ end | |
| 24 24 | 
             
            IncompleteTask.execute #=> raises CMDx::UndefinedMethodError
         | 
| 25 25 | 
             
            ```
         | 
| 26 26 |  | 
| 27 | 
            +
            ## Rollback
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            Undo any operations linked to the given status, helping to restore a pristine state.
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            ```ruby
         | 
| 32 | 
            +
            class ValidateDocument < CMDx::Task
         | 
| 33 | 
            +
              def work
         | 
| 34 | 
            +
                # Your logic here...
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              def rollback
         | 
| 38 | 
            +
                # Your undo logic...
         | 
| 39 | 
            +
              end
         | 
| 40 | 
            +
            end
         | 
| 41 | 
            +
            ```
         | 
| 42 | 
            +
             | 
| 27 43 | 
             
            ## Inheritance
         | 
| 28 44 |  | 
| 29 45 | 
             
            Share configuration across tasks using inheritance:
         | 
| @@ -65,3 +81,4 @@ Tasks follow a predictable execution pattern: | |
| 65 81 | 
             
            | **Execution** | `executing` | `success`/`failed`/`skipped` | `work` method runs |
         | 
| 66 82 | 
             
            | **Completion** | `executed` | `success`/`failed`/`skipped` | Result finalized |
         | 
| 67 83 | 
             
            | **Freezing** | `executed` | `success`/`failed`/`skipped` | Task becomes immutable |
         | 
| 84 | 
            +
            | **Rollback** | `executed` | `failed`/`skipped` | Work undone |
         | 
    
        data/docs/callbacks.md
    CHANGED
    
    
    
        data/docs/getting_started.md
    CHANGED
    
    | @@ -78,6 +78,16 @@ CMDx.configure do |config| | |
| 78 78 | 
             
            end
         | 
| 79 79 | 
             
            ```
         | 
| 80 80 |  | 
| 81 | 
            +
            ### Rollback
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            Control when a `rollback` of task execution is called.
         | 
| 84 | 
            +
             | 
| 85 | 
            +
            ```ruby
         | 
| 86 | 
            +
            CMDx.configure do |config|
         | 
| 87 | 
            +
              config.rollback_on = ["failed"] # String or Array[String]
         | 
| 88 | 
            +
            end
         | 
| 89 | 
            +
            ```
         | 
| 90 | 
            +
             | 
| 81 91 | 
             
            ### Backtraces
         | 
| 82 92 |  | 
| 83 93 | 
             
            Enable detailed backtraces for non-fault exceptions to improve debugging. Optionally clean up stack traces to remove framework noise.
         | 
| @@ -258,7 +268,8 @@ class GenerateInvoice < CMDx::Task | |
| 258 268 | 
             
                deprecated: true,                            # Task deprecations
         | 
| 259 269 | 
             
                retries: 3,                                  # Non-fault exception retries
         | 
| 260 270 | 
             
                retry_on: [External::ApiError],              # List of exceptions to retry on
         | 
| 261 | 
            -
                retry_jitter: 1 | 
| 271 | 
            +
                retry_jitter: 1,                             # Space between retry iteration, eg: current retry num + 1
         | 
| 272 | 
            +
                rollback_on: ["failed", "skipped"],          # Rollback on override
         | 
| 262 273 | 
             
              )
         | 
| 263 274 |  | 
| 264 275 | 
             
              def work
         | 
| @@ -269,7 +280,7 @@ end | |
| 269 280 |  | 
| 270 281 | 
             
            !!! warning "Important"
         | 
| 271 282 |  | 
| 272 | 
            -
                Retries reuse the same context. By default, all `StandardError` exceptions are retried unless you specify `retry_on | 
| 283 | 
            +
                Retries reuse the same context. By default, all `StandardError` exceptions (including faults) are retried unless you specify `retry_on` option for specific matches.
         | 
| 273 284 |  | 
| 274 285 | 
             
            ### Registrations
         | 
| 275 286 |  | 
    
        data/docs/retries.md
    ADDED
    
    | @@ -0,0 +1,121 @@ | |
| 1 | 
            +
            # Retries
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            CMDx provides automatic retry functionality for tasks that encounter transient failures. This is essential for handling temporary issues like network timeouts, rate limits, or database locks without manual intervention.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ## Basic Usage
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            Configure retries upto n attempts without any delay.
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ```ruby
         | 
| 10 | 
            +
            class FetchExternalData < CMDx::Task
         | 
| 11 | 
            +
              settings retries: 3
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              def work
         | 
| 14 | 
            +
                response = HTTParty.get("https://api.example.com/data")
         | 
| 15 | 
            +
                context.data = response.parsed_response
         | 
| 16 | 
            +
              end
         | 
| 17 | 
            +
            end
         | 
| 18 | 
            +
            ```
         | 
| 19 | 
            +
             | 
| 20 | 
            +
            When an exception occurs during execution, CMDx automatically retries up to the configured limit.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
            ## Selective Retries
         | 
| 23 | 
            +
             | 
| 24 | 
            +
            By default, CMDx retries on `StandardError` and its subclasses. Narrow this to specific exception types:
         | 
| 25 | 
            +
             | 
| 26 | 
            +
            ```ruby
         | 
| 27 | 
            +
            class ProcessPayment < CMDx::Task
         | 
| 28 | 
            +
              settings retries: 5, retry_on: [Stripe::RateLimitError, Net::ReadTimeout]
         | 
| 29 | 
            +
             | 
| 30 | 
            +
              def work
         | 
| 31 | 
            +
                # Your logic here...
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| 34 | 
            +
            ```
         | 
| 35 | 
            +
             | 
| 36 | 
            +
            !!! warning "Important"
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                Only exceptions matching the `retry_on` configuration will trigger retries. Uncaught exceptions immediately fail the task.
         | 
| 39 | 
            +
             | 
| 40 | 
            +
            ## Retry Jitter
         | 
| 41 | 
            +
             | 
| 42 | 
            +
            Add delays between retry attempts to avoid overwhelming external services or to implement exponential backoff strategies.
         | 
| 43 | 
            +
             | 
| 44 | 
            +
            ### Fixed Value
         | 
| 45 | 
            +
             | 
| 46 | 
            +
            Use a numeric value to calculate linear delay (`jitter * current_retry`):
         | 
| 47 | 
            +
             | 
| 48 | 
            +
            ```ruby
         | 
| 49 | 
            +
            class ImportRecords < CMDx::Task
         | 
| 50 | 
            +
              settings retries: 3, retry_jitter: 0.5
         | 
| 51 | 
            +
             | 
| 52 | 
            +
              def work
         | 
| 53 | 
            +
                # Delays: 0s, 0.5s (retry 1), 1.0s (retry 2), 1.5s (retry 3)
         | 
| 54 | 
            +
                context.records = ExternalAPI.fetch_records
         | 
| 55 | 
            +
              end
         | 
| 56 | 
            +
            end
         | 
| 57 | 
            +
            ```
         | 
| 58 | 
            +
             | 
| 59 | 
            +
            ### Symbol References
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            Define an instance method for custom delay logic:
         | 
| 62 | 
            +
             | 
| 63 | 
            +
            ```ruby
         | 
| 64 | 
            +
            class SyncInventory < CMDx::Task
         | 
| 65 | 
            +
              settings retries: 5, retry_jitter: :exponential_backoff
         | 
| 66 | 
            +
             | 
| 67 | 
            +
              def work
         | 
| 68 | 
            +
                context.inventory = InventoryAPI.sync
         | 
| 69 | 
            +
              end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
              private
         | 
| 72 | 
            +
             | 
| 73 | 
            +
              def exponential_backoff(current_retry)
         | 
| 74 | 
            +
                2 ** current_retry # 2s, 4s, 8s, 16s, 32s
         | 
| 75 | 
            +
              end
         | 
| 76 | 
            +
            end
         | 
| 77 | 
            +
            ```
         | 
| 78 | 
            +
             | 
| 79 | 
            +
            ### Proc or Lambda
         | 
| 80 | 
            +
             | 
| 81 | 
            +
            Pass a proc for inline delay calculations:
         | 
| 82 | 
            +
             | 
| 83 | 
            +
            ```ruby
         | 
| 84 | 
            +
            class PollJobStatus < CMDx::Task
         | 
| 85 | 
            +
              # Proc
         | 
| 86 | 
            +
              settings retries: 10, retry_jitter: proc { |retry_count| [retry_count * 0.5, 5.0].min }
         | 
| 87 | 
            +
             | 
| 88 | 
            +
              # Lambda
         | 
| 89 | 
            +
              settings retries: 10, retry_jitter: ->(retry_count) { [retry_count * 0.5, 5.0].min }
         | 
| 90 | 
            +
             | 
| 91 | 
            +
              def work
         | 
| 92 | 
            +
                # Delays: 0.5s, 1.0s, 1.5s, 2.0s, 2.5s, 3.0s, 3.5s, 4.0s, 4.5s, 5.0s (capped)
         | 
| 93 | 
            +
                context.status = JobAPI.check_status(context.job_id)
         | 
| 94 | 
            +
              end
         | 
| 95 | 
            +
            end
         | 
| 96 | 
            +
            ```
         | 
| 97 | 
            +
             | 
| 98 | 
            +
            ### Class or Module
         | 
| 99 | 
            +
             | 
| 100 | 
            +
            Implement reusable delay logic in dedicated modules and classes:
         | 
| 101 | 
            +
             | 
| 102 | 
            +
            ```ruby
         | 
| 103 | 
            +
            class ExponentialBackoff
         | 
| 104 | 
            +
              def call(task, retry_count)
         | 
| 105 | 
            +
                base_delay = task.context.base_delay || 1.0
         | 
| 106 | 
            +
                [base_delay * (2 ** retry_count), 60.0].min
         | 
| 107 | 
            +
              end
         | 
| 108 | 
            +
            end
         | 
| 109 | 
            +
             | 
| 110 | 
            +
            class FetchUserProfile < CMDx::Task
         | 
| 111 | 
            +
              # Class or Module
         | 
| 112 | 
            +
              settings retries: 4, retry_jitter: ExponentialBackoff
         | 
| 113 | 
            +
             | 
| 114 | 
            +
              # Instance
         | 
| 115 | 
            +
              settings retries: 4, retry_jitter: ExponentialBackoff.new
         | 
| 116 | 
            +
             | 
| 117 | 
            +
              def work
         | 
| 118 | 
            +
                # Your logic here...
         | 
| 119 | 
            +
              end
         | 
| 120 | 
            +
            end
         | 
| 121 | 
            +
            ```
         | 
    
        data/docs/tips_and_tricks.md
    CHANGED
    
    | @@ -145,7 +145,8 @@ class ConfigureCompany < CMDx::Task | |
| 145 145 | 
             
            end
         | 
| 146 146 | 
             
            ```
         | 
| 147 147 |  | 
| 148 | 
            -
            ##  | 
| 148 | 
            +
            ## More Examples
         | 
| 149 149 |  | 
| 150 150 | 
             
            - [Active Record Query Tagging](https://github.com/drexed/cmdx/blob/main/examples/active_record_query_tagging.md)
         | 
| 151 151 | 
             
            - [Paper Trail Whatdunnit](https://github.com/drexed/cmdx/blob/main/examples/paper_trail_whatdunnit.md)
         | 
| 152 | 
            +
            - [Stoplight Circuit Breaker](https://github.com/drexed/cmdx/blob/main/examples/stoplight_circuit_breaker.md)
         | 
| @@ -0,0 +1,36 @@ | |
| 1 | 
            +
            # Stoplight Circuit Breaker
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            Integrate circuit breakers to protect external service calls and prevent cascading failures when dependencies are unavailable.
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            <https://github.com/bolshakov/stoplight>
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ### Setup
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            ```ruby
         | 
| 10 | 
            +
            # lib/cmdx_stoplight_middleware.rb
         | 
| 11 | 
            +
            class CmdxStoplightMiddleware
         | 
| 12 | 
            +
              def self.call(task, **options, &)
         | 
| 13 | 
            +
                light = Stoplight(options[:name] || task.class.name, **options)
         | 
| 14 | 
            +
                light.run(&)
         | 
| 15 | 
            +
              rescue Stoplight::Error::RedLight => e
         | 
| 16 | 
            +
                task.result.tap { |r| r.fail!("[#{e.class}] #{e.message}", cause: e) }
         | 
| 17 | 
            +
              end
         | 
| 18 | 
            +
            end
         | 
| 19 | 
            +
            ```
         | 
| 20 | 
            +
             | 
| 21 | 
            +
            ### Usage
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            ```ruby
         | 
| 24 | 
            +
            class MyTask < CMDx::Task
         | 
| 25 | 
            +
              # With default options
         | 
| 26 | 
            +
              register :middleware, CmdxStoplightMiddleware
         | 
| 27 | 
            +
             | 
| 28 | 
            +
              # With stoplight options
         | 
| 29 | 
            +
              register :middleware, CmdxStoplightMiddleware, cool_off_time: 10
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              def work
         | 
| 32 | 
            +
                # Do work...
         | 
| 33 | 
            +
              end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            end
         | 
| 36 | 
            +
            ```
         | 
    
        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
         | 
| @@ -244,7 +246,7 @@ module CMDx | |
| 244 246 | 
             
                  invoke_callbacks(:on_bad) if task.result.bad?
         | 
| 245 247 | 
             
                end
         | 
| 246 248 |  | 
| 247 | 
            -
                # Finalizes execution by freezing the task and  | 
| 249 | 
            +
                # Finalizes execution by freezing the task, logging results, and rolling back work.
         | 
| 248 250 | 
             
                #
         | 
| 249 251 | 
             
                # @rbs () -> Result
         | 
| 250 252 | 
             
                def finalize_execution!
         | 
| @@ -253,6 +255,8 @@ module CMDx | |
| 253 255 |  | 
| 254 256 | 
             
                  freeze_execution!
         | 
| 255 257 | 
             
                  clear_chain!
         | 
| 258 | 
            +
             | 
| 259 | 
            +
                  rollback_execution!
         | 
| 256 260 | 
             
                end
         | 
| 257 261 |  | 
| 258 262 | 
             
                # Logs the execution result at the configured log level.
         | 
| @@ -309,5 +313,18 @@ module CMDx | |
| 309 313 | 
             
                  Chain.clear
         | 
| 310 314 | 
             
                end
         | 
| 311 315 |  | 
| 316 | 
            +
                # Rolls back the work of a task.
         | 
| 317 | 
            +
                #
         | 
| 318 | 
            +
                # @rbs () -> void
         | 
| 319 | 
            +
                def rollback_execution!
         | 
| 320 | 
            +
                  return unless task.respond_to?(:rollback)
         | 
| 321 | 
            +
             | 
| 322 | 
            +
                  statuses = task.class.settings[:rollback_on]
         | 
| 323 | 
            +
                  statuses = Array(statuses).map(&:to_s).uniq
         | 
| 324 | 
            +
                  return unless statuses.include?(task.result.status)
         | 
| 325 | 
            +
             | 
| 326 | 
            +
                  task.rollback
         | 
| 327 | 
            +
                end
         | 
| 328 | 
            +
             | 
| 312 329 | 
             
              end
         | 
| 313 330 | 
             
            end
         | 
    
        data/lib/cmdx/version.rb
    CHANGED
    
    
    
        data/mkdocs.yml
    CHANGED
    
    | @@ -2,7 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            site_name: CMDx
         | 
| 4 4 | 
             
            site_url: https://drexed.github.io/cmdx/
         | 
| 5 | 
            -
            site_description: Build business logic that's powerful, predictable, and  | 
| 5 | 
            +
            site_description: Build business logic that's powerful, predictable, and maintainable.
         | 
| 6 6 | 
             
            site_author: drexed
         | 
| 7 7 | 
             
            repo_name: drexed/cmdx
         | 
| 8 8 | 
             
            repo_url: https://github.com/drexed/cmdx
         | 
| @@ -108,9 +108,11 @@ nav: | |
| 108 108 | 
             
              - Middlewares: middlewares.md
         | 
| 109 109 | 
             
              - Logging: logging.md
         | 
| 110 110 | 
             
              - Internationalization: internationalization.md
         | 
| 111 | 
            +
              - Retries: retries.md
         | 
| 111 112 | 
             
              - Deprecation: deprecation.md
         | 
| 112 113 | 
             
              - Workflows: workflows.md
         | 
| 113 114 | 
             
              - Tips and Tricks: tips_and_tricks.md
         | 
| 115 | 
            +
              - LLM.md: https://raw.githubusercontent.com/drexed/cmdx/refs/heads/main/LLM.md
         | 
| 114 116 |  | 
| 115 117 | 
             
            extra:
         | 
| 116 118 | 
             
              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.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Juan Gomez
         | 
| @@ -240,11 +240,13 @@ files: | |
| 240 240 | 
             
            - docs/outcomes/result.md
         | 
| 241 241 | 
             
            - docs/outcomes/states.md
         | 
| 242 242 | 
             
            - docs/outcomes/statuses.md
         | 
| 243 | 
            +
            - docs/retries.md
         | 
| 243 244 | 
             
            - docs/stylesheets/extra.css
         | 
| 244 245 | 
             
            - docs/tips_and_tricks.md
         | 
| 245 246 | 
             
            - docs/workflows.md
         | 
| 246 247 | 
             
            - examples/active_record_query_tagging.md
         | 
| 247 248 | 
             
            - examples/paper_trail_whatdunnit.md
         | 
| 249 | 
            +
            - examples/stoplight_circuit_breaker.md
         | 
| 248 250 | 
             
            - lib/cmdx.rb
         | 
| 249 251 | 
             
            - lib/cmdx/.DS_Store
         | 
| 250 252 | 
             
            - lib/cmdx/attribute.rb
         |