Class: Sentry::GoodJob::CronHelpers::Integration

Inherits:
Object
  • Object
show all
Defined in:
lib/sentry/good_job/cron_helpers.rb

Overview

Main integration class that handles all cron monitoring setup This class follows Good Job’s integration patterns and Sentry’s extension guidelines

Class Method Summary collapse

Class Method Details

.add_monitoring_to_job(job_class, slug: nil, cron_expression: nil, timezone: nil) ⇒ Object

Manually add cron monitoring to a specific job



166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
# File 'lib/sentry/good_job/cron_helpers.rb', line 166

def self.add_monitoring_to_job(job_class, slug: nil, cron_expression: nil, timezone: nil)
  return unless ::Sentry.initialized?

  # Include Sentry::Cron::MonitorCheckIns module for cron monitoring
  # only patch if not explicitly included in job by user
  unless job_class.ancestors.include?(Sentry::Cron::MonitorCheckIns)
    job_class.include(Sentry::Cron::MonitorCheckIns)
  end

  # Create monitor config
  monitor_config = if cron_expression
    Sentry::GoodJob::CronHelpers::Helpers.monitor_config_from_cron(cron_expression, timezone: timezone)
  else
    # Default to hourly monitoring if no cron expression provided
    ::Sentry::Cron::MonitorConfig.from_crontab("0 * * * *")
  end

  if monitor_config
    monitor_slug = slug || Sentry::GoodJob::CronHelpers::Helpers.monitor_slug(job_class.name)

    job_class.sentry_monitor_check_ins(
      slug: monitor_slug,
      monitor_config: monitor_config
    )

    Sentry.configuration.sdk_logger.info "Added Sentry cron monitoring for #{job_class.name} (#{monitor_slug})"
  end
end

.attach_reload_hook_if_availableObject



195
196
197
198
199
200
201
202
203
204
205
206
# File 'lib/sentry/good_job/cron_helpers.rb', line 195

def self.attach_reload_hook_if_available
  return if @reload_hooked
  return unless defined?(::ActiveSupport::Reloader)

  ::ActiveSupport::Reloader.to_prepare do
    @setup_completed = false
  end

  @reload_hooked = true
rescue NameError
  # ActiveSupport::Reloader not available in this environment
end

.reset_setup_state!Object

Reset setup state (primarily for testing)



99
100
101
# File 'lib/sentry/good_job/cron_helpers.rb', line 99

def self.reset_setup_state!
  @setup_completed = false
end

.setup_monitoring_for_job(cron_key, job_config) ⇒ Object

Set up monitoring for a specific job



104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
# File 'lib/sentry/good_job/cron_helpers.rb', line 104

def self.setup_monitoring_for_job(cron_key, job_config)
  job_class_name = job_config[:class]
  cron_expression = job_config[:cron]

  return unless job_class_name && cron_expression

  # Defer job class constantization to avoid boot-time issues
  # The job class will be constantized when the job is actually executed
  # This prevents issues during development boot and circular dependencies

  # Store the monitoring configuration for later use
  # We'll set up the monitoring when the job class is first loaded
  deferred_setup = lambda do
    job_class = begin
      job_class_name.constantize
    rescue NameError => e
      Sentry.configuration.sdk_logger.warn "Could not find job class '#{job_class_name}' for Sentry cron monitoring: #{e.message}"
      return
    end

    # Include Sentry::Cron::MonitorCheckIns module for cron monitoring
    # only patch if not explicitly included in job by user
    unless job_class.ancestors.include?(Sentry::Cron::MonitorCheckIns)
      job_class.include(Sentry::Cron::MonitorCheckIns)
    end

    # Parse cron expression and create monitor config
    cron_without_tz, timezone = Sentry::GoodJob::CronHelpers::Helpers.parse_cron_with_timezone(cron_expression)
    monitor_config = Sentry::GoodJob::CronHelpers::Helpers.monitor_config_from_cron(cron_without_tz, timezone: timezone)

    if monitor_config
      # Configure Sentry cron monitoring - use cron_key as slug for consistency
      monitor_slug = Sentry::GoodJob::CronHelpers::Helpers.monitor_slug(cron_key)

      job_class.sentry_monitor_check_ins(
        slug: monitor_slug,
        monitor_config: monitor_config
      )

      job_class_name
    else
      Sentry.configuration.sdk_logger.warn "Could not create monitor config for #{job_class_name} with cron '#{cron_expression}'"
      nil
    end
  end

  # Set up monitoring when the job class is first loaded
  # This defers constantization until the job is actually needed
  if defined?(::Rails) && ::Rails.respond_to?(:application) && ::Rails.application
    ::Rails.application.config.after_initialize do
      deferred_setup.call
    end
  else
    # Fallback for non-Rails environments
    deferred_setup.call
  end

  # Return the job name for logging purposes
  job_class_name
end

.setup_monitoring_for_scheduled_jobsObject

Set up monitoring for all scheduled jobs from Good Job configuration



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/sentry/good_job/cron_helpers.rb', line 73

def self.setup_monitoring_for_scheduled_jobs
  return unless ::Sentry.initialized?
  return unless ::Sentry.configuration.good_job.enable_cron_monitors
  attach_reload_hook_if_available
  return if @setup_completed

  return unless defined?(::Rails) && ::Rails.respond_to?(:application) && ::Rails.application
  cron_config = ::Rails.application.config.good_job.cron
  return if cron_config.blank?

  added_jobs = []
  cron_config.each do |cron_key, job_config|
    job_name = setup_monitoring_for_job(cron_key, job_config)
    added_jobs << job_name if job_name
  end

  @setup_completed = true
  if added_jobs.any?
    job_list = added_jobs.join(", ")
    Sentry.configuration.sdk_logger.info "Sentry cron monitoring setup for #{added_jobs.size} scheduled jobs: #{job_list}"
  else
    Sentry.configuration.sdk_logger.info "Sentry cron monitoring setup for #{cron_config.keys.size} scheduled jobs"
  end
end