manager.rb 3.0 KB

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