12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- module MonitoringHelper
- class HealthChecker
- class DelayedJob < Backend
- FAILED_JOBS_THRESHOLD = 10
- TOTAL_JOBS_THRESHOLD = 8_000
- TOTAL_JOBS_TIMEOUT = 15.minutes
- def run_health_check
- failed_jobs
- failed_with_attempts
- total_jobs
- end
- private
- def scope
- Delayed::Job.where('attempts > 0')
- end
- def failed_jobs
- count_failed_jobs = scope.count
- return if count_failed_jobs <= FAILED_JOBS_THRESHOLD
- response.issues.push "#{count_failed_jobs} failing background jobs"
- end
- def failed_with_attempts
- scope
- .reorder(:created_at)
- .limit(10)
- .each_with_object({}) { |elem, memo| map_single_failed_job(elem, memo) }
- .sort
- .each_with_index do |(job_name, job_data), index|
- response.issues.push "Failed to run background job ##{index + 1} '#{job_name}' #{job_data[:count]} time(s) with #{job_data[:attempts]} attempt(s)."
- end
- end
- def map_single_failed_job(job, hash)
- job_name = job_name(job)
- hash[job_name] ||= {
- count: 0,
- attempts: 0,
- }
- hash[job_name][:count] += 1
- hash[job_name][:attempts] += job.attempts
- end
- def job_name(job)
- if job.instance_of?(Delayed::Backend::ActiveRecord::Job) && job.payload_object.respond_to?(:job_data)
- return job.payload_object.job_data['job_class']
- end
- job.name
- end
- def total_jobs
- total_jobs = Delayed::Job.where(created_at: ...TOTAL_JOBS_TIMEOUT.ago).count
- return if total_jobs <= TOTAL_JOBS_THRESHOLD
- response.issues.push "#{total_jobs} background jobs in queue"
- end
- end
- end
- end
|