123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120 |
- # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
- class BackgroundServices
- class Service
- class ProcessScheduledJobs
- class Manager
- attr_reader :job, :jobs_container
- def initialize(job, jobs_container)
- @job = job
- @jobs_container = jobs_container
- end
- def run
- return if skip?
- jobs_container[job.id] = start
- end
- private
- def skip?
- return true if skip_already_running?
- # check job.last_run
- return true if skip_job_last_run?
- # timeplan is optional
- # but if timeplan is present
- return true if skip_job_timeplan?
- false
- end
- def skip_already_running?
- return false if thread.blank?
- status = thread.try(:status)
- if status.blank?
- invalid_thread_log(thread, status)
- jobs_container.delete(job.id)
- return false
- end
- log_already_running(status)
- true
- end
- def log_already_running(status)
- Rails.logger.info "Running job thread for '#{job.name}' (#{job.method}) status is: #{status}"
- end
- def skip_job_last_run?
- return false if !job.last_run || !job.period
- job.last_run > (Time.zone.now - job.period)
- end
- def skip_job_timeplan?
- return false if job.timeplan.blank?
- !job.in_timeplan?(Time.zone.now)
- end
- def thread
- jobs_container[job.id]
- end
- def start
- Thread.new do
- Rails.application.executor.wrap do
- start_in_thread
- end
- rescue => e
- Rails.logger.error e
- jobs_container.delete(job.id)
- end
- end
- def start_in_thread
- ApplicationHandleInfo.use('scheduler') do
- Rails.logger.debug { "Started job thread for '#{job.name}' (#{job.method})..." }
- JobExecutor.run(job)
- wrapup
- end
- end
- def wrapup
- job.update! pid: ''
- Rails.logger.debug { " ...stopped thread for '#{job.method}'" }
- # release thread lock and remove thread handle
- jobs_container.delete(job.id)
- end
- def build_invalid_thread_log(thread, status)
- if thread.respond_to?(:status)
- return "Invalid thread stored for job '#{job.name}' (#{job.method}): #{thread.inspect}. Deleting and resting job."
- end
- how = if status.nil?
- 'via an exception'
- elsif status == false
- 'normally'
- else
- 'unknownly'
- end
- "Job thread terminated #{how} found for '#{job.name}' (#{job.method}). This should not happen. Please report."
- end
- def invalid_thread_log(thread, status)
- Rails.logger.error build_invalid_thread_log(thread, status)
- end
- end
- end
- end
- end
|