debian-mirror-gitlab/lib/gitlab/sidekiq_status.rb

131 lines
3.7 KiB
Ruby
Raw Normal View History

2018-12-13 13:39:08 +05:30
# frozen_string_literal: true
2017-08-17 22:00:37 +05:30
module Gitlab
# The SidekiqStatus module and its child classes can be used for checking if a
# Sidekiq job has been processed or not.
#
# To check if a job has been completed, simply pass the job ID to the
# `completed?` method:
#
2021-12-11 22:18:48 +05:30
# job_id = SomeWorker.with_status.perform_async(...)
2017-08-17 22:00:37 +05:30
#
# if Gitlab::SidekiqStatus.completed?(job_id)
# ...
# end
#
2021-12-11 22:18:48 +05:30
# If you do not use `with_status`, and the worker class does not declare
# `status_expiration` in its `sidekiq_options`, then this status will not be
# stored.
#
2017-08-17 22:00:37 +05:30
# For each job ID registered a separate key is stored in Redis, making lookups
# much faster than using Sidekiq's built-in job finding/status API. These keys
# expire after a certain period of time to prevent storing too many keys in
# Redis.
module SidekiqStatus
2019-12-04 20:38:33 +05:30
STATUS_KEY = 'gitlab-sidekiq-status:%s'
2017-08-17 22:00:37 +05:30
# The default time (in seconds) after which a status key is expired
# automatically. The default of 30 minutes should be more than sufficient
# for most jobs.
DEFAULT_EXPIRATION = 30.minutes.to_i
2022-01-26 12:08:38 +05:30
DEFAULT_VALUE = 1
DEFAULT_VALUE_MESSAGE = 'Keys using the default value for SidekiqStatus detected'
2017-08-17 22:00:37 +05:30
# Starts tracking of the given job.
#
# jid - The Sidekiq job ID
# expire - The expiration time of the Redis key.
2022-01-26 12:08:38 +05:30
def self.set(jid, expire = DEFAULT_EXPIRATION, value: DEFAULT_VALUE)
2017-08-17 22:00:37 +05:30
Sidekiq.redis do |redis|
2022-01-26 12:08:38 +05:30
redis.set(key_for(jid), value, ex: expire)
2017-08-17 22:00:37 +05:30
end
end
# Stops the tracking of the given job.
#
# jid - The Sidekiq job ID to remove.
def self.unset(jid)
Sidekiq.redis do |redis|
redis.del(key_for(jid))
end
end
# Returns true if all the given job have been completed.
#
# job_ids - The Sidekiq job IDs to check.
#
# Returns true or false.
def self.all_completed?(job_ids)
2020-10-24 23:57:45 +05:30
self.num_running(job_ids) == 0
2017-08-17 22:00:37 +05:30
end
2019-09-30 21:07:59 +05:30
# Returns true if the given job is running or enqueued.
2018-03-17 18:26:18 +05:30
#
# job_id - The Sidekiq job ID to check.
def self.running?(job_id)
num_running([job_id]) > 0
end
2019-09-30 21:07:59 +05:30
# Returns the number of jobs that are running or enqueued.
2017-08-17 22:00:37 +05:30
#
# job_ids - The Sidekiq job IDs to check.
def self.num_running(job_ids)
responses = self.job_status(job_ids)
2021-06-08 01:23:25 +05:30
responses.count(&:present?)
2017-08-17 22:00:37 +05:30
end
# Returns the number of jobs that have completed.
#
# job_ids - The Sidekiq job IDs to check.
def self.num_completed(job_ids)
job_ids.size - self.num_running(job_ids)
end
# Returns the job status for each of the given job IDs.
#
# job_ids - The Sidekiq job IDs to check.
#
# Returns an array of true or false indicating job completion.
2019-09-30 21:07:59 +05:30
# true = job is still running or enqueued
2017-08-17 22:00:37 +05:30
# false = job completed
def self.job_status(job_ids)
2022-01-26 12:08:38 +05:30
return [] if job_ids.empty?
2017-08-17 22:00:37 +05:30
keys = job_ids.map { |jid| key_for(jid) }
2022-01-26 12:08:38 +05:30
results = Sidekiq.redis { |redis| redis.mget(*keys) }
2017-08-17 22:00:37 +05:30
2022-01-26 12:08:38 +05:30
if Feature.enabled?(:log_implicit_sidekiq_status_calls, default_enabled: :yaml)
to_log = keys.zip(results).select do |_key, result|
result == DEFAULT_VALUE.to_s
end.map(&:first)
Sidekiq.logger.info(message: DEFAULT_VALUE_MESSAGE, keys: to_log) if to_log.any?
2017-08-17 22:00:37 +05:30
end
2022-01-26 12:08:38 +05:30
results.map { |result| !result.nil? }
2017-08-17 22:00:37 +05:30
end
# Returns the JIDs that are completed
#
# job_ids - The Sidekiq job IDs to check.
#
# Returns an array of completed JIDs
def self.completed_jids(job_ids)
2018-03-17 18:26:18 +05:30
statuses = job_status(job_ids)
completed = []
job_ids.zip(statuses).each do |job_id, status|
completed << job_id unless status
2017-08-17 22:00:37 +05:30
end
2018-03-17 18:26:18 +05:30
completed
2017-08-17 22:00:37 +05:30
end
def self.key_for(jid)
STATUS_KEY % jid
end
end
end