Module: LogStruct::Integrations::ActionMailer::ErrorHandling

Extended by:
ActiveSupport::Concern, T::Sig
Defined in:
lib/log_struct/integrations/action_mailer/error_handling.rb

Overview

Handles error handling for ActionMailer

IMPORTANT LIMITATIONS:

  1. This module must be included BEFORE users define rescue_from handlers to ensure proper handler precedence (user handlers are checked first)
  2. Rails rescue_from handlers don't bubble to parent class handlers after reraise
  3. Handler order matters: Rails checks rescue_from handlers in reverse declaration order

Defined Under Namespace

Modules: ClassMethods

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#logstruct_mail_failed ⇒ Boolean?

Returns:

  • (Boolean, nil)


76
77
78
# File 'lib/log_struct/integrations/action_mailer/error_handling.rb', line 76

def logstruct_mail_failed
  @logstruct_mail_failed
end

Class Method Details

.handle_mailer_class_error(mailer_class, error, report:, reraise:) ⇒ void

This method returns an undefined value.

An error that reaches the class handler from the delivery itself was logged (and reported) by the mailer's handler, which raised it again (log_and_reraise_error). It's raised again, without logging it twice, so the job fails as deliver_now would.

Parameters:

  • mailer_class (T.untyped)
  • error (StandardError)
  • report (Boolean)
  • reraise (Boolean)


55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
# File 'lib/log_struct/integrations/action_mailer/error_handling.rb', line 55

def self.handle_mailer_class_error(mailer_class, error, report:, reraise:)
  Kernel.raise error if LogStruct::LoggedErrors.logged?(error)

  message = if reraise
    "#{error.class}: Email delivery failed. Error message: #{error.message}"
  else
    "#{error.class}: Cannot send email. Error message: #{error.message}"
  end
  LogStruct.error(Log::ActionMailer::Error.new(
    mailer_class: mailer_class.to_s,
    error_class: error.class,
    message: message,
    backtrace: error.backtrace,
    level: Level::Error
  ))
  LogStruct.report_error(error, source: Source::Mailer, context: {mailer_class: mailer_class.to_s}) if report

  Kernel.raise error if reraise
end

.install_handler(base) ⇒ void

This method returns an undefined value.

This will be called when the module is included/prepended

Parameters:

  • base (T.untyped)


84
85
86
87
88
89
90
91
92
93
# File 'lib/log_struct/integrations/action_mailer/error_handling.rb', line 84

def self.install_handler(base)
  # Only add the handler once per class
  return if base.instance_variable_get(:@_logstruct_handler_installed)

  # Add our handler FIRST so it has lower priority than user handlers
  base.rescue_from StandardError, with: :log_and_reraise_error

  # Mark as installed to prevent duplicates
  base.instance_variable_set(:@_logstruct_handler_installed, true)
end

.prepended(base) ⇒ void

This method returns an undefined value.

Also support prepended (used by tests and manual setup)

Parameters:

  • base (T.untyped)


101
102
103
# File 'lib/log_struct/integrations/action_mailer/error_handling.rb', line 101

def self.prepended(base)
  install_handler(base)
end

.report_before_reraise? ⇒ Boolean

log_and_reraise_error reports the error where standard_errors' mode reports the app's errors (Report, and ReportProduction in production). Elsewhere whatever rescues the raised error decides.

Returns:

  • (Boolean)


46
47
48
49
# File 'lib/log_struct/integrations/action_mailer/error_handling.rb', line 46

def self.report_before_reraise?
  mode = LogStruct.error_handling_mode_for(Source::Mailer)
  mode == ErrorHandlingMode::Report || (mode == ErrorHandlingMode::ReportProduction && LogStruct.is_production?)
end

Instance Method Details

#log_and_ignore_error(ex) ⇒ void (protected)

This method returns an undefined value.

Logs the error, and doesn't report or raise it

Parameters:

  • ex (StandardError)


109
110
111
112
# File 'lib/log_struct/integrations/action_mailer/error_handling.rb', line 109

def log_and_ignore_error(ex)
  self.logstruct_mail_failed = true
  log_email_delivery_error(ex, notify: false, report: false, reraise: false)
end

#log_and_report_error(ex) ⇒ void (protected)

This method returns an undefined value.

Logs and reports the error, and doesn't raise it

Parameters:

  • ex (StandardError)


116
117
118
# File 'lib/log_struct/integrations/action_mailer/error_handling.rb', line 116

def log_and_report_error(ex)
  log_email_delivery_error(ex, notify: false, report: true, reraise: false)
end

#log_and_reraise_error(ex) ⇒ void (protected)

This method returns an undefined value.

Logs the error and raises it again, reporting it too in the Report modes (report_before_reraise?)

Parameters:

  • ex (StandardError)


122
123
124
# File 'lib/log_struct/integrations/action_mailer/error_handling.rb', line 122

def log_and_reraise_error(ex)
  log_email_delivery_error(ex, notify: false, report: ErrorHandling.report_before_reraise?, reraise: true)
end