2020-09-21 11:09:44 -04:00
|
|
|
# frozen_string_literal: true
|
|
|
|
|
|
|
|
module Gitlab
|
|
|
|
module Ci
|
|
|
|
module Runner
|
|
|
|
##
|
|
|
|
# Runner Backoff class is an implementation of an exponential backoff
|
|
|
|
# used when a runner communicates with GitLab. We typically use it when a
|
|
|
|
# runner retries sending a build status after we created a build pending
|
|
|
|
# state.
|
|
|
|
#
|
|
|
|
# Backoff is calculated based on the backoff slot which is always a power
|
|
|
|
# of 2:
|
|
|
|
#
|
|
|
|
# 0s - 3s duration -> 1 second backoff
|
|
|
|
# 4s - 7s duration -> 2 seconds backoff
|
|
|
|
# 8s - 15s duration -> 4 seconds backoff
|
|
|
|
# 16s - 31s duration -> 8 seconds backoff
|
|
|
|
# 32s - 63s duration -> 16 seconds backoff
|
|
|
|
# 64s - 127s duration -> 32 seconds backoff
|
|
|
|
# 127s - 256s+ duration -> 64 seconds backoff
|
|
|
|
#
|
|
|
|
# It means that first 15 requests made by a runner will need to respect
|
|
|
|
# following backoffs:
|
|
|
|
#
|
|
|
|
# 0s -> 1 second backoff (backoff started, slot 0, 2^0 backoff)
|
|
|
|
# 1s -> 1 second backoff
|
|
|
|
# 2s -> 1 second backoff
|
|
|
|
# 3s -> 1 seconds backoff
|
|
|
|
# (slot 1 - 2^1 backoff)
|
|
|
|
# 4s -> 2 seconds backoff
|
|
|
|
# 6s -> 2 seconds backoff
|
|
|
|
# (slot 2 - 2^2 backoff)
|
|
|
|
# 8s -> 4 seconds backoff
|
|
|
|
# 12s -> 4 seconds backoff
|
|
|
|
# (slot 3 - 2^3 backoff)
|
|
|
|
# 16s -> 8 seconds backoff
|
|
|
|
# 24s -> 8 seconds backoff
|
|
|
|
# (slot 4 - 2^4 backoff)
|
|
|
|
# 32s -> 16 seconds backoff
|
|
|
|
# 48s -> 16 seconds backoff
|
|
|
|
# (slot 5 - 2^5 backoff)
|
|
|
|
# 64s -> 32 seconds backoff
|
|
|
|
# 96s -> 32 seconds backoff
|
|
|
|
# (slot 6 - 2^6 backoff)
|
|
|
|
# 128s -> 64 seconds backoff
|
|
|
|
#
|
|
|
|
# There is a cap on the backoff - it will never exceed 64 seconds.
|
|
|
|
#
|
|
|
|
class Backoff
|
|
|
|
def initialize(started)
|
|
|
|
@started = started
|
|
|
|
|
|
|
|
if duration < 0
|
|
|
|
raise ArgumentError, 'backoff duration negative'
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
def duration
|
2020-09-30 11:09:46 -04:00
|
|
|
(Time.current - @started).ceil
|
2020-09-21 11:09:44 -04:00
|
|
|
end
|
|
|
|
|
|
|
|
def slot
|
2020-09-30 11:09:46 -04:00
|
|
|
return 0 if duration < 2
|
2020-09-21 11:09:44 -04:00
|
|
|
|
|
|
|
Math.log(duration, 2).floor - 1
|
|
|
|
end
|
|
|
|
|
|
|
|
def to_seconds
|
|
|
|
2**[slot, 6].min
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|