Module: RailsFlowMap::ErrorHandler

Extended by:
ErrorHandler
Included in:
ErrorHandler
Defined in:
lib/rails_flow_map/errors.rb

Overview

Error handling utilities

Constant Summary collapse

MAX_RETRIES =

Maximum number of retry attempts for transient errors

3
RETRYABLE_ERRORS =

Errors that can be retried

[
  Errno::ENOENT,
  Errno::EACCES,
  Errno::EAGAIN,
  Errno::EWOULDBLOCK
].freeze

Instance Method Summary collapse

Instance Method Details

#handle_error(error, operation, context = {}) ⇒ Object

Convert standard errors to RailsFlowMap errors with context

Parameters:

  • error (Exception)

    The original error

  • operation (String)

    Description of the operation that failed

  • context (Hash) (defaults to: {})

    Additional context

Raises:



161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
# File 'lib/rails_flow_map/errors.rb', line 161

def handle_error(error, operation, context = {})
  error_context = context.merge(
    operation: operation,
    original_error: error.class.name
  )

  rails_flow_map_error = case error
  when JSON::ParserError, YAML::SyntaxError
    GraphParseError.new("Failed to parse data during #{operation}: #{error.message}", context: error_context)
  when Errno::ENOENT, Errno::EACCES
    FileOperationError.new("File operation failed during #{operation}: #{error.message}", context: error_context)
  when ArgumentError
    InvalidInputError.new("Invalid input during #{operation}: #{error.message}", context: error_context)
  when SystemStackError
    ResourceLimitError.new("Stack overflow during #{operation}, input too complex", context: error_context)
  when NoMemoryError
    ResourceLimitError.new("Out of memory during #{operation}", context: error_context)
  else
    Error.new("Unexpected error during #{operation}: #{error.message}", context: error_context)
  end

  Logging.log_error(rails_flow_map_error, context: error_context)
  raise rails_flow_map_error
end

#retryable?(error) ⇒ Boolean

Check if an error is retryable

Parameters:

  • error (Exception)

    The error to check

Returns:

  • (Boolean)

    True if the error can be retried



213
214
215
# File 'lib/rails_flow_map/errors.rb', line 213

def retryable?(error)
  RETRYABLE_ERRORS.any? { |retryable_class| error.is_a?(retryable_class) }
end

#user_friendly_message(error) ⇒ String

Extract user-friendly error message from any error

Parameters:

  • error (Exception)

    The error to extract message from

Returns:

  • (String)

    User-friendly error message



221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
# File 'lib/rails_flow_map/errors.rb', line 221

def user_friendly_message(error)
  case error
  when RailsFlowMap::GraphParseError
    "Failed to parse the graph data. Please check your input format."
  when RailsFlowMap::FileOperationError
    "File operation failed. Please check file permissions and paths."
  when RailsFlowMap::InvalidInputError
    "Invalid input provided. #{error.message}"
  when RailsFlowMap::SecurityError
    "Security validation failed. Operation blocked for safety."
  when RailsFlowMap::ResourceLimitError
    "Operation exceeded resource limits. Please try with smaller input."
  when RailsFlowMap::Error
    error.message
  else
    "An unexpected error occurred. Please try again."
  end
end

#validate_input!(validations, context: {}) ⇒ Object

Validate input parameters and raise errors if invalid

Parameters:

  • validations (Hash)

    Hash of parameter_name => validation_proc pairs

  • context (Hash) (defaults to: {})

    Additional context for error reporting

Raises:



191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
# File 'lib/rails_flow_map/errors.rb', line 191

def validate_input!(validations, context: {})
  validations.each do |param_name, validation|
    begin
      next if validation.call
    rescue => e
      raise InvalidInputError.new(
        "Validation failed for parameter '#{param_name}': #{e.message}",
        context: context.merge(parameter: param_name)
      )
    end

    raise InvalidInputError.new(
      "Invalid value for parameter '#{param_name}'",
      context: context.merge(parameter: param_name)
    )
  end
end

#with_error_handling(operation, context: {}, retries: MAX_RETRIES) { ... } ⇒ Object

Execute a block with comprehensive error handling

Parameters:

  • operation (String)

    Description of the operation

  • context (Hash) (defaults to: {})

    Additional context for error reporting

  • retries (Integer) (defaults to: MAX_RETRIES)

    Number of retry attempts for transient errors

Yields:

  • The block to execute

Returns:

  • The result of the block

Raises:



130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
# File 'lib/rails_flow_map/errors.rb', line 130

def with_error_handling(operation, context: {}, retries: MAX_RETRIES)
  attempt = 0

  begin
    Logging.with_context(operation: operation, **context) do
      yield
    end
  rescue *RETRYABLE_ERRORS => e
    attempt += 1
    if attempt <= retries
      Logging.logger.warn("Retrying #{operation} (attempt #{attempt}/#{retries}): #{e.message}")
      sleep(0.1 * attempt) # Exponential backoff
      retry
    else
      handle_error(e, operation, context.merge(max_retries_exceeded: true))
    end
  rescue RailsFlowMap::Error => e
    # Already a RailsFlowMap error, just log and re-raise
    Logging.log_error(e, context: context.merge(operation: operation))
    raise
  rescue => e
    handle_error(e, operation, context)
  end
end