manager.rb 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. class BackgroundServices
  3. class Service
  4. class ProcessScheduledJobs
  5. class Manager
  6. attr_reader :job, :jobs_container
  7. def initialize(job, jobs_container)
  8. @job = job
  9. @jobs_container = jobs_container
  10. end
  11. def run
  12. return if skip?
  13. jobs_container[job.id] = start
  14. end
  15. private
  16. def skip?
  17. return true if BackgroundServices.shutdown_requested
  18. return true if skip_already_running?
  19. # check job.last_run
  20. return true if skip_job_last_run?
  21. # timeplan is optional
  22. # but if timeplan is present
  23. return true if skip_job_timeplan?
  24. false
  25. end
  26. def skip_already_running?
  27. return false if thread.blank?
  28. status = thread.try(:status)
  29. if status.blank?
  30. invalid_thread_log(thread, status)
  31. jobs_container.delete(job.id)
  32. return false
  33. end
  34. log_already_running(status)
  35. true
  36. end
  37. def log_already_running(status)
  38. Rails.logger.info "Running job thread for '#{job.name}' (#{job.method}) status is: #{status}"
  39. end
  40. def skip_job_last_run?
  41. return false if !job.last_run || !job.period
  42. job.last_run > (Time.zone.now - job.period)
  43. end
  44. def skip_job_timeplan?
  45. return false if job.timeplan.blank?
  46. !job.in_timeplan?(Time.zone.now)
  47. end
  48. def thread
  49. jobs_container[job.id]
  50. end
  51. def start
  52. Thread.new do
  53. Rails.application.executor.wrap do
  54. start_in_thread
  55. end
  56. rescue => e
  57. Rails.logger.error e
  58. jobs_container.delete(job.id)
  59. end
  60. end
  61. def start_in_thread
  62. ApplicationHandleInfo.use('scheduler') do
  63. Rails.logger.debug { "Started job thread for '#{job.name}' (#{job.method})..." }
  64. JobExecutor.run(job)
  65. wrapup
  66. end
  67. end
  68. def wrapup
  69. job.update! pid: ''
  70. Rails.logger.debug { " ...stopped thread for '#{job.method}'" }
  71. # release thread lock and remove thread handle
  72. jobs_container.delete(job.id)
  73. end
  74. def build_invalid_thread_log(thread, status)
  75. if thread.respond_to?(:status)
  76. return "Invalid thread stored for job '#{job.name}' (#{job.method}): #{thread.inspect}. Deleting and resting job."
  77. end
  78. how = if status.nil?
  79. 'via an exception'
  80. elsif status == false
  81. 'normally'
  82. else
  83. 'unknownly'
  84. end
  85. "Job thread terminated #{how} found for '#{job.name}' (#{job.method}). This should not happen. Please report."
  86. end
  87. def invalid_thread_log(thread, status)
  88. Rails.logger.error build_invalid_thread_log(thread, status)
  89. end
  90. end
  91. end
  92. end
  93. end