Class: RailsOnboarding::ErrorRecovery
- Inherits:
-
Object
- Object
- RailsOnboarding::ErrorRecovery
- Defined in:
- lib/rails_onboarding/error_recovery.rb
Overview
Error Recovery Service Handles failed steps gracefully with retry logic and error state management
Constant Summary collapse
- MAX_RETRIES =
3- RETRY_DELAY =
2.seconds
Class Method Summary collapse
-
.clear_error_state(user, action) ⇒ Object
Clear error state for a successful action.
-
.failed_actions(user) ⇒ Object
Get failed actions for a user.
-
.has_errors?(user) ⇒ Boolean
Check if user has any failed actions.
-
.mark_as_failed(user, action, error) ⇒ Object
Mark an action as failed after all retries.
-
.record_error(user, action, error, attempt) ⇒ Object
Record an error for analytics and debugging.
-
.reset_errors(user) ⇒ Object
Reset all errors for a user.
-
.retry_failed_action(user, action, &block) ⇒ Object
Retry a failed action.
-
.with_exponential_backoff(max_attempts: 3, base_delay: 1, max_delay: 30, exponential_base: 2) ⇒ Object
Retry with exponential backoff.
-
.with_fallback(fallback_value = nil) ⇒ Object
Execute with fallback value.
-
.with_recovery(user, action, max_retries: MAX_RETRIES) { ... } ⇒ Boolean
Execute a block with error recovery.
-
.with_timeout(seconds: 30) ⇒ Object
Execute with timeout.
Class Method Details
.clear_error_state(user, action) ⇒ Object
Clear error state for a successful action
92 93 94 95 96 97 98 99 100 |
# File 'lib/rails_onboarding/error_recovery.rb', line 92 def clear_error_state(user, action) return unless user if user.respond_to?(:onboarding_failed_actions) user.onboarding_failed_actions ||= [] user.onboarding_failed_actions.reject! { |a| a[:action] == action.to_s } user.save(validate: false) rescue nil end end |
.failed_actions(user) ⇒ Object
Get failed actions for a user
109 110 111 112 |
# File 'lib/rails_onboarding/error_recovery.rb', line 109 def failed_actions(user) return [] unless user&.respond_to?(:onboarding_failed_actions) user.onboarding_failed_actions || [] end |
.has_errors?(user) ⇒ Boolean
Check if user has any failed actions
103 104 105 106 |
# File 'lib/rails_onboarding/error_recovery.rb', line 103 def has_errors?(user) return false unless user&.respond_to?(:onboarding_failed_actions) user.onboarding_failed_actions&.any? || false end |
.mark_as_failed(user, action, error) ⇒ Object
Mark an action as failed after all retries
75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/rails_onboarding/error_recovery.rb', line 75 def mark_as_failed(user, action, error) return unless user if user.respond_to?(:onboarding_failed_actions) user.onboarding_failed_actions ||= [] user.onboarding_failed_actions << { action: action.to_s, error: error&., failed_at: Time.current.iso8601 } user.save(validate: false) rescue nil end Rails.logger.error("Action #{action} failed for user #{user.id} after all retries") end |
.record_error(user, action, error, attempt) ⇒ Object
Record an error for analytics and debugging
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/rails_onboarding/error_recovery.rb', line 46 def record_error(user, action, error, attempt) return unless user && error error_data = { action: action.to_s, error_class: error.class.name, error_message: error., attempt: attempt, timestamp: Time.current.iso8601 } # Store in user's error log if available if user.respond_to?(:onboarding_errors) user.onboarding_errors ||= [] user.onboarding_errors << error_data user.save(validate: false) rescue nil end # Track in analytics if defined?(RailsOnboarding::AnalyticsEvent) RailsOnboarding::AnalyticsEvent.track_custom_event( user: user, event_name: "onboarding_error", event_data: error_data ) end end |
.reset_errors(user) ⇒ Object
Reset all errors for a user
121 122 123 124 125 126 127 128 129 130 131 132 133 |
# File 'lib/rails_onboarding/error_recovery.rb', line 121 def reset_errors(user) return unless user if user.respond_to?(:onboarding_errors=) user.onboarding_errors = [] end if user.respond_to?(:onboarding_failed_actions=) user.onboarding_failed_actions = [] end user.save(validate: false) rescue nil end |
.retry_failed_action(user, action, &block) ⇒ Object
Retry a failed action
115 116 117 118 |
# File 'lib/rails_onboarding/error_recovery.rb', line 115 def retry_failed_action(user, action, &block) clear_error_state(user, action) with_recovery(user, action, &block) end |
.with_exponential_backoff(max_attempts: 3, base_delay: 1, max_delay: 30, exponential_base: 2) ⇒ Object
Retry with exponential backoff
136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 |
# File 'lib/rails_onboarding/error_recovery.rb', line 136 def with_exponential_backoff(max_attempts: 3, base_delay: 1, max_delay: 30, exponential_base: 2) attempt = 0 begin attempt += 1 yield rescue StandardError => e if attempt < max_attempts delay = [ base_delay * (exponential_base ** (attempt - 1)), max_delay ].min Rails.logger.warn "Attempt #{attempt} failed: #{e.}. Retrying in #{delay}s..." sleep delay retry else Rails.logger.error "All #{max_attempts} attempts failed: #{e.}" raise end end end |
.with_fallback(fallback_value = nil) ⇒ Object
Execute with fallback value
165 166 167 168 169 170 |
# File 'lib/rails_onboarding/error_recovery.rb', line 165 def with_fallback(fallback_value = nil) yield rescue StandardError => e Rails.logger.warn "Operation failed, using fallback: #{e.}" fallback_value end |
.with_recovery(user, action, max_retries: MAX_RETRIES) { ... } ⇒ Boolean
Execute a block with error recovery
16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 |
# File 'lib/rails_onboarding/error_recovery.rb', line 16 def with_recovery(user, action, max_retries: MAX_RETRIES, &block) attempt = 0 last_error = nil loop do attempt += 1 begin result = block.call clear_error_state(user, action) return result rescue StandardError => e last_error = e Rails.logger.error("Error in #{action} (attempt #{attempt}/#{max_retries}): #{e.}") Rails.logger.error(e.backtrace.join("\n")) if Rails.env.development? record_error(user, action, e, attempt) break if attempt >= max_retries sleep RETRY_DELAY if defined?(sleep) end end # All retries failed mark_as_failed(user, action, last_error) false end |
.with_timeout(seconds: 30) ⇒ Object
Execute with timeout
155 156 157 158 159 160 161 162 |
# File 'lib/rails_onboarding/error_recovery.rb', line 155 def with_timeout(seconds: 30) Timeout.timeout(seconds) do yield end rescue Timeout::Error => e Rails.logger.error "Operation timed out after #{seconds} seconds" raise end |