import_job.rb 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  1. # Copyright (C) 2012-2016 Zammad Foundation, http://zammad-foundation.org/
  2. class ImportJob < ApplicationModel
  3. store :payload
  4. store :result
  5. # Starts the import backend class based on the name attribute.
  6. # Import backend class is initialized with the current instance.
  7. # Logs the start and end time (if ended successfully) and logs
  8. # exceptions into result if they happen.
  9. #
  10. # @example
  11. # import = ImportJob.new(name: 'Import::Ldap', payload: Setting.get('ldap_config'))
  12. # import.start
  13. #
  14. # return [nil]
  15. def start
  16. self.started_at = Time.zone.now
  17. save
  18. instance = name.constantize.new(self)
  19. instance.start
  20. rescue => e
  21. Rails.logger.error e
  22. # rubocop:disable Style/RedundantSelf
  23. if !self.result.is_a?(Hash)
  24. self.result = {}
  25. end
  26. self.result[:error] = e.message
  27. # rubocop:enable Style/RedundantSelf
  28. ensure
  29. self.finished_at = Time.zone.now
  30. save
  31. end
  32. # Gets called when the Scheduler gets (re-)started and this job was still
  33. # in the queue. If `finished_at` is blank the call is piped through to
  34. # the ImportJob backend which has to decide how to go from here. The delayed
  35. # job will get destroyed if rescheduled? is not implemented
  36. # as an ImportJob backend class method.
  37. #
  38. # @see Scheduler#cleanup_delayed
  39. #
  40. # @example
  41. # import.reschedule?(delayed_job)
  42. #
  43. # return [Boolean] whether the ImportJob should get rescheduled (true) or destroyed (false)
  44. def reschedule?(delayed_job)
  45. return false if finished_at.present?
  46. instance = name.constantize.new(self)
  47. return false if !instance.respond_to?(:reschedule?)
  48. instance.reschedule?(delayed_job)
  49. end
  50. # Convenience wrapper around the start method for starting (delayed) dry runs.
  51. # Logs the start and end time (if ended successfully) and logs
  52. # exceptions into result if they happen.
  53. # Only one running or pending dry run per backend is possible at the same time.
  54. #
  55. # @param [Hash] params the params used to initialize the ImportJob instance.
  56. # @option params [Boolean] :delay Defines if job should get executed delayed. Default is true.
  57. # @example
  58. # import = ImportJob.dry_run(name: 'Import::Ldap', payload: Setting.get('ldap_config'), delay: false)
  59. #
  60. # return [nil]
  61. def self.dry_run(params)
  62. return if exists?(name: params[:name], dry_run: true, finished_at: nil)
  63. params[:dry_run] = true
  64. instance = create(params.except(:delay))
  65. if params.fetch(:delay, true)
  66. instance.delay.start
  67. else
  68. instance.start
  69. end
  70. end
  71. # Queues and starts all import backends as import jobs.
  72. #
  73. # @example
  74. # ImportJob.start_registered
  75. #
  76. # return [nil]
  77. def self.start_registered
  78. queue_registered
  79. start
  80. end
  81. # Starts all import jobs that have not started yet and are no dry runs.
  82. #
  83. # @example
  84. # ImportJob.start
  85. #
  86. # return [nil]
  87. def self.start
  88. where(started_at: nil, dry_run: false).each(&:start)
  89. end
  90. # Queues all configured import backends from Setting 'import_backends' as import jobs
  91. # that are not yet queued. Backends which are not #queueable? are skipped.
  92. #
  93. # @example
  94. # ImportJob.queue_registered
  95. #
  96. # return [nil]
  97. def self.queue_registered
  98. import_backends = Setting.get('import_backends')
  99. return if import_backends.blank?
  100. import_backends.each do |backend|
  101. if !backend_valid?(backend)
  102. Rails.logger.error "Invalid import backend '#{backend}'"
  103. next
  104. end
  105. # skip backends that are not "ready" yet
  106. next if !backend.constantize.queueable?
  107. # skip if no entry exists
  108. # skip if a not finished entry exists
  109. next if ImportJob.exists?(name: backend, finished_at: nil)
  110. ImportJob.create(name: backend)
  111. end
  112. end
  113. # Checks if the given import backend is valid.
  114. #
  115. # @example
  116. # ImportJob.backend_valid?('Import::Ldap')
  117. # # => true
  118. #
  119. # return [Boolean]
  120. def self.backend_valid?(backend)
  121. backend.constantize
  122. true
  123. rescue NameError
  124. false
  125. end
  126. end