diff options
Diffstat (limited to 'app/models/ci/unlock_pipeline_request.rb')
-rw-r--r-- | app/models/ci/unlock_pipeline_request.rb | 53 |
1 files changed, 53 insertions, 0 deletions
diff --git a/app/models/ci/unlock_pipeline_request.rb b/app/models/ci/unlock_pipeline_request.rb new file mode 100644 index 00000000000..c8fc82f3e55 --- /dev/null +++ b/app/models/ci/unlock_pipeline_request.rb @@ -0,0 +1,53 @@ +# frozen_string_literal: true + +module Ci + class UnlockPipelineRequest + QUEUE_REDIS_KEY = 'ci_unlock_pipeline_requests:queue' + + def self.enqueue(pipeline_id) + unix_timestamp = Time.current.utc.to_i + pipeline_ids = Array(pipeline_id).uniq + pipeline_ids_with_scores = pipeline_ids.map do |id| + # The order of values per pair is `[score, key]`, so in this case, the unix timestamp is the score. + # By default, the sort order of sorted sets is from lowest to highest, though this does not matter much + # because we use `ZPOPMIN` to make sure to return the lowest/oldest request in terms of unix timestamp score. + [unix_timestamp, id] + end + + with_redis do |redis| + added = redis.zadd(QUEUE_REDIS_KEY, pipeline_ids_with_scores, nx: true) + log_event(:enqueued, pipeline_ids) if added > 0 + added + end + end + + def self.next! + with_redis do |redis| + pipeline_id, enqueue_timestamp = redis.zpopmin(QUEUE_REDIS_KEY) + break unless pipeline_id + + pipeline_id = pipeline_id.to_i + log_event(:picked_next, pipeline_id) + + [pipeline_id, enqueue_timestamp.to_i] + end + end + + def self.total_pending + with_redis do |redis| + redis.zcard(QUEUE_REDIS_KEY) + end + end + + def self.with_redis(&block) + Gitlab::Redis::SharedState.with(&block) + end + + def self.log_event(event, pipeline_id) + Gitlab::AppLogger.info( + message: "Pipeline unlock - #{event}", + pipeline_id: pipeline_id + ) + end + end +end |