diff options
Diffstat (limited to 'app/workers/stuck_export_jobs_worker.rb')
-rw-r--r-- | app/workers/stuck_export_jobs_worker.rb | 54 |
1 files changed, 54 insertions, 0 deletions
diff --git a/app/workers/stuck_export_jobs_worker.rb b/app/workers/stuck_export_jobs_worker.rb new file mode 100644 index 00000000000..6d8d60d2fc0 --- /dev/null +++ b/app/workers/stuck_export_jobs_worker.rb @@ -0,0 +1,54 @@ +# frozen_string_literal: true + +# rubocop:disable Scalability/IdempotentWorker +class StuckExportJobsWorker + include ApplicationWorker + # rubocop:disable Scalability/CronWorkerContext + # This worker updates export states inline and does not schedule + # other jobs. + include CronjobQueue + # rubocop:enable Scalability/CronWorkerContext + + feature_category :importers + worker_resource_boundary :cpu + + EXPORT_JOBS_EXPIRATION = 6.hours.to_i + + def perform + failed_jobs_count = mark_stuck_jobs_as_failed! + + Gitlab::Metrics.add_event(:stuck_export_jobs, + failed_jobs_count: failed_jobs_count) + end + + private + + # rubocop: disable CodeReuse/ActiveRecord + def mark_stuck_jobs_as_failed! + jids_and_ids = enqueued_exports.pluck(:jid, :id).to_h + + completed_jids = Gitlab::SidekiqStatus.completed_jids(jids_and_ids.keys) + return unless completed_jids.any? + + completed_ids = jids_and_ids.values_at(*completed_jids) + + # We select the export states again, because they may have transitioned from + # started to finished while we were looking up their Sidekiq status. + completed_jobs = enqueued_exports.where(id: completed_ids) + + Sidekiq.logger.info( + message: 'Marked stuck export jobs as failed', + job_ids: completed_jobs.map(&:jid) + ) + + completed_jobs.each do |job| + job.fail_op + end.count + end + # rubocop: enable CodeReuse/ActiveRecord + + def enqueued_exports + ProjectExportJob.with_status([:started, :queued]) + end +end +# rubocop:enable Scalability/IdempotentWorker |