import_job.rb 4.4 KB

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