inst-jobs-statsd 2.1.1 → 3.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/lib/inst-jobs-statsd.rb +22 -18
- data/lib/inst_jobs_statsd/default_tracking.rb +3 -1
- data/lib/inst_jobs_statsd/ext/job.rb +2 -0
- data/lib/inst_jobs_statsd/jobs_tracker.rb +4 -0
- data/lib/inst_jobs_statsd/naming.rb +19 -24
- data/lib/inst_jobs_statsd/stats/counters/complete.rb +23 -0
- data/lib/inst_jobs_statsd/stats/counters/create.rb +23 -0
- data/lib/inst_jobs_statsd/stats/counters/run.rb +2 -0
- data/lib/inst_jobs_statsd/stats/counters.rb +2 -0
- data/lib/inst_jobs_statsd/stats/periodic/failed.rb +2 -0
- data/lib/inst_jobs_statsd/stats/periodic/queue.rb +3 -1
- data/lib/inst_jobs_statsd/stats/periodic/run.rb +3 -1
- data/lib/inst_jobs_statsd/stats/periodic.rb +6 -2
- data/lib/inst_jobs_statsd/stats/timing/failed.rb +2 -0
- data/lib/inst_jobs_statsd/stats/timing/perform.rb +2 -0
- data/lib/inst_jobs_statsd/stats/timing/pop.rb +2 -0
- data/lib/inst_jobs_statsd/stats/timing.rb +7 -3
- data/lib/inst_jobs_statsd/version.rb +3 -1
- metadata +88 -97
- data/spec/factories/jobs.rb +0 -9
- data/spec/factories/workers.rb +0 -9
- data/spec/gemfiles/42.gemfile +0 -8
- data/spec/gemfiles/42.gemfile.lock +0 -206
- data/spec/gemfiles/51.gemfile +0 -8
- data/spec/gemfiles/51.gemfile.lock +0 -231
- data/spec/gemfiles/60.gemfile +0 -7
- data/spec/gemfiles/60.gemfile.lock +0 -259
- data/spec/inst_jobs_statsd/ext/job_spec.rb +0 -15
- data/spec/inst_jobs_statsd/jobs_tracker_spec.rb +0 -28
- data/spec/inst_jobs_statsd/naming_spec.rb +0 -56
- data/spec/inst_jobs_statsd/stats/counters/run_spec.rb +0 -27
- data/spec/inst_jobs_statsd/stats/periodic/failed_spec.rb +0 -31
- data/spec/inst_jobs_statsd/stats/periodic/queue_spec.rb +0 -95
- data/spec/inst_jobs_statsd/stats/periodic/run_spec.rb +0 -53
- data/spec/inst_jobs_statsd/stats/periodic_spec.rb +0 -63
- data/spec/inst_jobs_statsd/stats/timing/failed_spec.rb +0 -25
- data/spec/inst_jobs_statsd/stats/timing/perform_spec.rb +0 -35
- data/spec/inst_jobs_statsd/stats/timing/pop_spec.rb +0 -34
- data/spec/inst_jobs_statsd/stats/timing_spec.rb +0 -35
- data/spec/inst_statsd/default_tracking_spec.rb +0 -16
- data/spec/matchers.rb +0 -3
- data/spec/setup_test_db.rb +0 -49
- data/spec/spec_helper.rb +0 -61
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: d5760a670863e6b529a17f1443c45b360ed9762b35ad9fe432a4bd66c5b3e90d
         | 
| 4 | 
            +
              data.tar.gz: 0efe20cd91f2dcb8cb55b5f4df13c372aa2f1b60ff2401c5379a453ed16e1bae
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 1a35e512b5a4b8a1e87205fa97a03922d70b95298635dda6d5778e9bcd110bb02b74dfd36791a963ca169dddbaafcac448c2e33beb1d640b27955f793138d990
         | 
| 7 | 
            +
              data.tar.gz: bd8808fa5e79266049f4cc9852df42c8bea046fc19d96c0402831df006e1c2a982a8d0475f12ac603bc0b0baf7224585546f78b79b3a650611f06d67cc1fe283
         | 
    
        data/lib/inst-jobs-statsd.rb
    CHANGED
    
    | @@ -1,25 +1,29 @@ | |
| 1 | 
            -
             | 
| 2 | 
            -
            require 'inst_statsd'
         | 
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 3 2 |  | 
| 4 | 
            -
             | 
| 3 | 
            +
            require "inst-jobs"
         | 
| 4 | 
            +
            require "inst_statsd"
         | 
| 5 5 |  | 
| 6 | 
            -
            require_relative  | 
| 7 | 
            -
            require_relative 'inst_jobs_statsd/jobs_tracker'
         | 
| 6 | 
            +
            require_relative "inst_jobs_statsd/version"
         | 
| 8 7 |  | 
| 9 | 
            -
            require_relative  | 
| 8 | 
            +
            require_relative "inst_jobs_statsd/default_tracking"
         | 
| 9 | 
            +
            require_relative "inst_jobs_statsd/jobs_tracker"
         | 
| 10 10 |  | 
| 11 | 
            -
            require_relative  | 
| 12 | 
            -
            require_relative 'inst_jobs_statsd/stats/counters/run'
         | 
| 11 | 
            +
            require_relative "inst_jobs_statsd/naming"
         | 
| 13 12 |  | 
| 14 | 
            -
            require_relative  | 
| 15 | 
            -
            require_relative  | 
| 16 | 
            -
            require_relative  | 
| 17 | 
            -
            require_relative  | 
| 13 | 
            +
            require_relative "inst_jobs_statsd/stats/counters"
         | 
| 14 | 
            +
            require_relative "inst_jobs_statsd/stats/counters/create"
         | 
| 15 | 
            +
            require_relative "inst_jobs_statsd/stats/counters/run"
         | 
| 16 | 
            +
            require_relative "inst_jobs_statsd/stats/counters/complete"
         | 
| 18 17 |  | 
| 19 | 
            -
            require_relative  | 
| 20 | 
            -
            require_relative  | 
| 21 | 
            -
            require_relative  | 
| 22 | 
            -
            require_relative  | 
| 23 | 
            -
            require_relative 'inst_jobs_statsd/ext/job'
         | 
| 18 | 
            +
            require_relative "inst_jobs_statsd/stats/periodic"
         | 
| 19 | 
            +
            require_relative "inst_jobs_statsd/stats/periodic/failed"
         | 
| 20 | 
            +
            require_relative "inst_jobs_statsd/stats/periodic/queue"
         | 
| 21 | 
            +
            require_relative "inst_jobs_statsd/stats/periodic/run"
         | 
| 24 22 |  | 
| 25 | 
            -
             | 
| 23 | 
            +
            require_relative "inst_jobs_statsd/stats/timing"
         | 
| 24 | 
            +
            require_relative "inst_jobs_statsd/stats/timing/failed"
         | 
| 25 | 
            +
            require_relative "inst_jobs_statsd/stats/timing/perform"
         | 
| 26 | 
            +
            require_relative "inst_jobs_statsd/stats/timing/pop"
         | 
| 27 | 
            +
            require_relative "inst_jobs_statsd/ext/job"
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            InstStatsd::DefaultTracking.include InstJobsStatsd::DefaultTracking
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            # Defines InstStatsd::DefaultTracking.track_jobs
         | 
| 2 4 | 
             
            # to be consistent with InstStatsd::DefaultTracking.track_sql etc
         | 
| 3 5 | 
             
            module InstJobsStatsd
         | 
| @@ -8,7 +10,7 @@ module InstJobsStatsd | |
| 8 10 |  | 
| 9 11 | 
             
                module ClassMethods
         | 
| 10 12 | 
             
                  def track_jobs(enable_periodic_queries: true)
         | 
| 11 | 
            -
                    @jobs_tracker ||= JobsTracker.new(enable_periodic_queries: enable_periodic_queries)
         | 
| 13 | 
            +
                    @jobs_tracker ||= JobsTracker.new(enable_periodic_queries: enable_periodic_queries) # rubocop:disable Naming/MemoizedInstanceVariableName
         | 
| 12 14 | 
             
                  end
         | 
| 13 15 | 
             
                end
         | 
| 14 16 | 
             
              end
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module InstJobsStatsd
         | 
| 2 4 | 
             
              class JobsTracker
         | 
| 3 5 | 
             
                def self.track(enable_periodic_queries: true)
         | 
| @@ -9,7 +11,9 @@ module InstJobsStatsd | |
| 9 11 | 
             
                end
         | 
| 10 12 |  | 
| 11 13 | 
             
                def initialize(enable_periodic_queries: true)
         | 
| 14 | 
            +
                  Stats::Counters::Create.enable
         | 
| 12 15 | 
             
                  Stats::Counters::Run.enable
         | 
| 16 | 
            +
                  Stats::Counters::Complete.enable
         | 
| 13 17 | 
             
                  ::Delayed::Job.prepend InstJobsStatsd::Ext::Job
         | 
| 14 18 |  | 
| 15 19 | 
             
                  if enable_periodic_queries
         | 
| @@ -1,6 +1,8 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module InstJobsStatsd
         | 
| 2 4 | 
             
              module Naming
         | 
| 3 | 
            -
                BASENAME =  | 
| 5 | 
            +
                BASENAME = "delayedjob"
         | 
| 4 6 |  | 
| 5 7 | 
             
                # The root prefix for all stat names
         | 
| 6 8 | 
             
                # TODO: Make this configurable
         | 
| @@ -8,10 +10,6 @@ module InstJobsStatsd | |
| 8 10 | 
             
                  BASENAME
         | 
| 9 11 | 
             
                end
         | 
| 10 12 |  | 
| 11 | 
            -
                def self.configure(strand_filter: nil)
         | 
| 12 | 
            -
                  @strand_filter = strand_filter
         | 
| 13 | 
            -
                end
         | 
| 14 | 
            -
             | 
| 15 13 | 
             
                def self.qualified_names(stat_name, job)
         | 
| 16 14 | 
             
                  names = ["#{basename}.#{stat_name}"]
         | 
| 17 15 | 
             
                  tagged = tagged_stat(names[0], job)
         | 
| @@ -37,29 +35,27 @@ module InstJobsStatsd | |
| 37 35 | 
             
                def self.dd_job_tags(job)
         | 
| 38 36 | 
             
                  tags = dd_region_tags
         | 
| 39 37 | 
             
                  return tags unless job
         | 
| 40 | 
            -
             | 
| 38 | 
            +
             | 
| 39 | 
            +
                  tags[:cluster] = job.current_shard&.database_server&.id if job.respond_to?(:current_shard)
         | 
| 40 | 
            +
                  tags[:priority] = job.priority
         | 
| 41 | 
            +
                  tags.compact!
         | 
| 42 | 
            +
             | 
| 41 43 | 
             
                  return tags unless job.tag
         | 
| 42 | 
            -
                  return tags if job.tag | 
| 44 | 
            +
                  return tags if job.tag.include?("Class:0x")
         | 
| 43 45 |  | 
| 44 46 | 
             
                  method_tag, obj_tag = split_to_tag(job)
         | 
| 45 47 | 
             
                  tag = obj_tag
         | 
| 46 | 
            -
                  tag = [obj_tag, method_tag].join( | 
| 48 | 
            +
                  tag = [obj_tag, method_tag].join(".") if method_tag.present?
         | 
| 47 49 | 
             
                  tags[:tag] = tag
         | 
| 48 50 | 
             
                  tags
         | 
| 49 51 | 
             
                end
         | 
| 50 52 |  | 
| 51 | 
            -
                def self.custom_tags(job, tags)
         | 
| 52 | 
            -
                  tags[:jobshard] = job.shard.id if job.respond_to?(:shard)
         | 
| 53 | 
            -
                  tags[:strand] = job.strand if job&.strand && @strand_filter&.call(job)
         | 
| 54 | 
            -
                  tags
         | 
| 55 | 
            -
                end
         | 
| 56 | 
            -
             | 
| 57 53 | 
             
                # this converts Foo#bar" or "Foo.bar" into "Foo and "bar",
         | 
| 58 54 | 
             
                # and makes sure the values are valid to be used for statsd names
         | 
| 59 55 | 
             
                def self.job_tags(job)
         | 
| 60 56 | 
             
                  return unless job
         | 
| 61 57 | 
             
                  return unless job.tag
         | 
| 62 | 
            -
                  return if job.tag | 
| 58 | 
            +
                  return if job.tag.include?("Class:0x")
         | 
| 63 59 |  | 
| 64 60 | 
             
                  method_tag, obj_tag = split_to_tag(job)
         | 
| 65 61 | 
             
                  tags = [obj_tag]
         | 
| @@ -70,26 +66,25 @@ module InstJobsStatsd | |
| 70 66 | 
             
                # We are using all existing stat names here because we do not want
         | 
| 71 67 | 
             
                # to break existing dependencies on the non-regioned data
         | 
| 72 68 | 
             
                def self.region_tags(stat_names)
         | 
| 73 | 
            -
                  return unless ENV[ | 
| 69 | 
            +
                  return unless ENV["INST_JOBS_STATSD_NAMESPACE"]
         | 
| 74 70 |  | 
| 75 71 | 
             
                  stat_names.map do |name|
         | 
| 76 72 | 
             
                    name
         | 
| 77 | 
            -
                      .split( | 
| 78 | 
            -
                      .insert(2, ENV[ | 
| 79 | 
            -
                      .join( | 
| 73 | 
            +
                      .split(".")
         | 
| 74 | 
            +
                      .insert(2, ENV["INST_JOBS_STATSD_NAMESPACE"])
         | 
| 75 | 
            +
                      .join(".")
         | 
| 80 76 | 
             
                  end
         | 
| 81 77 | 
             
                end
         | 
| 82 78 |  | 
| 83 79 | 
             
                def self.dd_region_tags
         | 
| 84 | 
            -
                  return {} unless ENV[ | 
| 85 | 
            -
                  { namespace: ENV['INST_JOBS_STATSD_NAMESPACE'] }
         | 
| 86 | 
            -
                end
         | 
| 80 | 
            +
                  return {} unless ENV["INST_JOBS_STATSD_NAMESPACE"]
         | 
| 87 81 |  | 
| 88 | 
            -
             | 
| 82 | 
            +
                  { namespace: ENV["INST_JOBS_STATSD_NAMESPACE"] }
         | 
| 83 | 
            +
                end
         | 
| 89 84 |  | 
| 90 85 | 
             
                def self.split_to_tag(job)
         | 
| 91 86 | 
             
                  obj_tag, method_tag = job.tag.split(/[\.#]/, 2).map do |v|
         | 
| 92 | 
            -
                    InstStatsd::Statsd.escape(v).gsub( | 
| 87 | 
            +
                    InstStatsd::Statsd.escape(v).gsub("::", "-")
         | 
| 93 88 | 
             
                  end
         | 
| 94 89 | 
             
                  [method_tag, obj_tag]
         | 
| 95 90 | 
             
                end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module InstJobsStatsd
         | 
| 4 | 
            +
              module Stats
         | 
| 5 | 
            +
                module Counters
         | 
| 6 | 
            +
                  module Complete
         | 
| 7 | 
            +
                    def self.enable
         | 
| 8 | 
            +
                      enable_complete_count
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    def self.enable_complete_count
         | 
| 12 | 
            +
                      Delayed::Worker.lifecycle.after(:perform) do |_worker, job|
         | 
| 13 | 
            +
                        report_complete_count(job)
         | 
| 14 | 
            +
                      end
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    def self.report_complete_count(job)
         | 
| 18 | 
            +
                      Counters.report_count(:complete, 1, job: job)
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -0,0 +1,23 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module InstJobsStatsd
         | 
| 4 | 
            +
              module Stats
         | 
| 5 | 
            +
                module Counters
         | 
| 6 | 
            +
                  module Create
         | 
| 7 | 
            +
                    def self.enable
         | 
| 8 | 
            +
                      enable_create_count
         | 
| 9 | 
            +
                    end
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                    def self.enable_create_count
         | 
| 12 | 
            +
                      Delayed::Worker.lifecycle.after(:create) do |_, result:|
         | 
| 13 | 
            +
                        report_create_count(result)
         | 
| 14 | 
            +
                      end
         | 
| 15 | 
            +
                    end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                    def self.report_create_count(job)
         | 
| 18 | 
            +
                      Counters.report_count(:create, 1, job: job)
         | 
| 19 | 
            +
                    end
         | 
| 20 | 
            +
                  end
         | 
| 21 | 
            +
                end
         | 
| 22 | 
            +
              end
         | 
| 23 | 
            +
            end
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module InstJobsStatsd
         | 
| 2 4 | 
             
              module Stats
         | 
| 3 5 | 
             
                module Periodic
         | 
| @@ -35,7 +37,7 @@ module InstJobsStatsd | |
| 35 37 | 
             
                      jobs_run_at = queued_jobs_scope.limit(10_000).pluck(:run_at)
         | 
| 36 38 | 
             
                      age_secs = jobs_run_at.map { |t| Delayed::Job.db_time_now - t }
         | 
| 37 39 | 
             
                      Periodic.report_gauge(:queue_age_total, age_secs.sum)
         | 
| 38 | 
            -
                      Periodic.report_gauge(:queue_age_max, age_secs.max)
         | 
| 40 | 
            +
                      Periodic.report_gauge(:queue_age_max, age_secs.max || 0)
         | 
| 39 41 | 
             
                    end
         | 
| 40 42 |  | 
| 41 43 | 
             
                    def self.queued_jobs_scope
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module InstJobsStatsd
         | 
| 2 4 | 
             
              module Stats
         | 
| 3 5 | 
             
                module Periodic
         | 
| @@ -26,7 +28,7 @@ module InstJobsStatsd | |
| 26 28 | 
             
                      jobs_run_at = running_jobs_scope.limit(10_000).pluck(:run_at)
         | 
| 27 29 | 
             
                      age_secs = jobs_run_at.map { |t| Delayed::Job.db_time_now - t }
         | 
| 28 30 | 
             
                      Periodic.report_gauge(:run_age_total, age_secs.sum)
         | 
| 29 | 
            -
                      Periodic.report_gauge(:run_age_max, age_secs.max)
         | 
| 31 | 
            +
                      Periodic.report_gauge(:run_age_max, age_secs.max || 0)
         | 
| 30 32 | 
             
                    end
         | 
| 31 33 |  | 
| 32 34 | 
             
                    def self.running_jobs_scope
         | 
| @@ -1,12 +1,15 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module InstJobsStatsd
         | 
| 2 4 | 
             
              module Stats
         | 
| 3 5 | 
             
                module Periodic
         | 
| 4 6 | 
             
                  def self.enable_callbacks
         | 
| 5 | 
            -
                    @instance ||= Callbacks.new
         | 
| 7 | 
            +
                    @instance ||= Callbacks.new # rubocop:disable Naming/MemoizedInstanceVariableName
         | 
| 6 8 | 
             
                  end
         | 
| 7 9 |  | 
| 8 10 | 
             
                  def self.add(proc)
         | 
| 9 11 | 
             
                    return unless @instance
         | 
| 12 | 
            +
             | 
| 10 13 | 
             
                    @instance.add(proc)
         | 
| 11 14 | 
             
                  end
         | 
| 12 15 |  | 
| @@ -72,6 +75,7 @@ module InstJobsStatsd | |
| 72 75 | 
             
                    # When the required interval of time has passed, execute the given block
         | 
| 73 76 | 
             
                    def tick
         | 
| 74 77 | 
             
                      return unless Delayed::Job.db_time_now >= @next_run
         | 
| 78 | 
            +
             | 
| 75 79 | 
             
                      update_next_run
         | 
| 76 80 | 
             
                      yield
         | 
| 77 81 | 
             
                    end
         | 
| @@ -83,7 +87,7 @@ module InstJobsStatsd | |
| 83 87 | 
             
                    # from the target interval as much as possible
         | 
| 84 88 | 
             
                    def update_next_run
         | 
| 85 89 | 
             
                      ticks = ((Delayed::Job.db_time_now - @start_time) / @min_interval).floor
         | 
| 86 | 
            -
                      @next_run = @start_time + (ticks + 1) * @min_interval
         | 
| 90 | 
            +
                      @next_run = @start_time + ((ticks + 1) * @min_interval)
         | 
| 87 91 | 
             
                    end
         | 
| 88 92 | 
             
                  end
         | 
| 89 93 | 
             
                end
         | 
| @@ -1,11 +1,13 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module InstJobsStatsd
         | 
| 2 4 | 
             
              module Stats
         | 
| 3 5 | 
             
                module Timing
         | 
| 4 | 
            -
                  def self.report_timing(stat, job: nil, timing: nil, sample_rate: 1)
         | 
| 6 | 
            +
                  def self.report_timing(stat, job: nil, timing: nil, sample_rate: 1, &block)
         | 
| 5 7 | 
             
                    stats = Naming.qualified_names(stat, job)
         | 
| 6 8 |  | 
| 7 | 
            -
                    if  | 
| 8 | 
            -
                      InstStatsd::Statsd.time(stats, sample_rate, short_stat: stat, tags: Naming.dd_job_tags(job)) | 
| 9 | 
            +
                    if block
         | 
| 10 | 
            +
                      InstStatsd::Statsd.time(stats, sample_rate, short_stat: stat, tags: Naming.dd_job_tags(job), &block)
         | 
| 9 11 | 
             
                    else
         | 
| 10 12 | 
             
                      InstStatsd::Statsd.timing(stats, timing, sample_rate, short_stat: stat, tags: Naming.dd_job_tags(job))
         | 
| 11 13 | 
             
                    end
         | 
| @@ -13,12 +15,14 @@ module InstJobsStatsd | |
| 13 15 |  | 
| 14 16 | 
             
                  def self.report_job_timing_queued(job)
         | 
| 15 17 | 
             
                    return unless job
         | 
| 18 | 
            +
             | 
| 16 19 | 
             
                    time_in_queue = ((Delayed::Job.db_time_now - job.run_at) * 1000).round
         | 
| 17 20 | 
             
                    report_timing(:queue, job: job, timing: time_in_queue)
         | 
| 18 21 | 
             
                  end
         | 
| 19 22 |  | 
| 20 23 | 
             
                  def self.report_job_timing_failed(job)
         | 
| 21 24 | 
             
                    return unless job
         | 
| 25 | 
            +
             | 
| 22 26 | 
             
                    time_to_failure = ((Delayed::Job.db_time_now - job.run_at) * 1000).round
         | 
| 23 27 | 
             
                    report_timing(:failed_after, job: job, timing: time_to_failure)
         | 
| 24 28 | 
             
                  end
         |