Module: Sentry::GoodJob::CronHelpers::Helpers

Defined in:
lib/sentry/good_job/cron_helpers.rb

Overview

Utility methods for cron parsing and configuration These methods handle the conversion between Good Job cron expressions and Sentry monitor configs

Class Method Summary collapse

Class Method Details

.monitor_config_from_cron(cron_expression, timezone: nil) ⇒ Object

Parse cron expression and create Sentry monitor config



14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
# File 'lib/sentry/good_job/cron_helpers.rb', line 14

def self.monitor_config_from_cron(cron_expression, timezone: nil)
  return nil unless cron_expression && !cron_expression.strip.empty?

  # Parse cron expression using fugit (same as Good Job)
  parsed_cron = Fugit.parse_cron(cron_expression)
  return nil unless parsed_cron

  # Convert to Sentry monitor config
  if timezone && !timezone.strip.empty?
    ::Sentry::Cron::MonitorConfig.from_crontab(cron_expression, timezone: timezone)
  else
    ::Sentry::Cron::MonitorConfig.from_crontab(cron_expression)
  end
rescue => e
  Sentry.configuration.sdk_logger.warn "Failed to parse cron expression '#{cron_expression}': #{e.message}"
  nil
end

.monitor_slug(job_name) ⇒ Object

Generate monitor slug from job name



33
34
35
# File 'lib/sentry/good_job/cron_helpers.rb', line 33

def self.monitor_slug(job_name)
  job_name.to_s.underscore.gsub(/_job$/, "")
end

.parse_cron_with_timezone(cron_expression) ⇒ Object

Parse cron expression and extract timezone



38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/sentry/good_job/cron_helpers.rb', line 38

def self.parse_cron_with_timezone(cron_expression)
  return [cron_expression, nil] unless cron_expression && !cron_expression.strip.empty?

  parts = cron_expression.strip.split(" ")
  return [cron_expression, nil] unless parts.length > 5

  # Last part might be timezone
  timezone = parts.last
  # Comprehensive timezone validation that handles:
  # - Standard timezone names (UTC, GMT)
  # - IANA timezone identifiers (America/New_York, Europe/Stockholm)
  # - Multi-level IANA timezones (America/Argentina/Buenos_Aires)
  # - UTC offsets (UTC+2, UTC-5, GMT+1, GMT-8)
  # - Numeric timezones (GMT-5, UTC+2)
  if timezone.match?(/^[A-Za-z_]+$/) || # Simple timezone names (UTC, GMT, EST, etc.)
      timezone.match?(/^[A-Za-z_]+\/[A-Za-z_]+$/) || # Single slash timezones (Europe/Stockholm)
      timezone.match?(/^[A-Za-z_]+\/[A-Za-z_]+\/[A-Za-z_]+$/) || # Multi-slash timezones (America/Argentina/Buenos_Aires)
      timezone.match?(/^[A-Za-z_]+[+-]\d+$/) || # UTC/GMT offsets (UTC+2, GMT-5)
      timezone.match?(/^[A-Za-z_]+\/[A-Za-z_]+[+-]\d+$/) # IANA with offset (Europe/Stockholm+1)
    cron_without_timezone = cron_expression.gsub(/\s+#{Regexp.escape(timezone)}$/, "")
    [cron_without_timezone, timezone]
  else
    [cron_expression, nil]
  end
end