53 lines
1.5 KiB
Ruby
53 lines
1.5 KiB
Ruby
# frozen_string_literal: true
|
||
|
||
class Captain::Lifecycle::Guards::QuietHours < Captain::Lifecycle::Guards::Base
|
||
MAX_DELAY = 2.hours
|
||
|
||
def check
|
||
config = Captain::Lifecycle::Config.for_account(@account)
|
||
return pass unless config.quiet_hours_enabled
|
||
return pass unless in_quiet_window?(@delivery.fire_at, config)
|
||
|
||
delayed_to = next_valid_time(@delivery.fire_at, config)
|
||
delay = delayed_to - @delivery.fire_at
|
||
return skip('too_stale') if delay > MAX_DELAY
|
||
|
||
reschedule(delayed_to)
|
||
end
|
||
|
||
private
|
||
|
||
def in_quiet_window?(time, config)
|
||
from_min = to_minutes(config.quiet_hours_from)
|
||
to_min = to_minutes(config.quiet_hours_to)
|
||
cur_min = (time.hour * 60) + time.min
|
||
|
||
if from_min < to_min
|
||
# Same-day window (e.g. 14:00–18:00)
|
||
cur_min >= from_min && cur_min < to_min
|
||
else
|
||
# Crosses midnight (e.g. 23:00–08:00)
|
||
cur_min >= from_min || cur_min < to_min
|
||
end
|
||
end
|
||
|
||
def next_valid_time(fire_at, config)
|
||
to_min = to_minutes(config.quiet_hours_to)
|
||
from_min = to_minutes(config.quiet_hours_from)
|
||
fire_min = (fire_at.hour * 60) + fire_at.min
|
||
|
||
# Base target: today at quiet_hours_to
|
||
target = fire_at.beginning_of_day + to_min.minutes
|
||
|
||
# If window crosses midnight AND fire_at is in the evening half (>= from),
|
||
# the window end ("to") is tomorrow morning.
|
||
target += 1.day if from_min > to_min && fire_min >= from_min
|
||
|
||
target
|
||
end
|
||
|
||
def to_minutes(time_value)
|
||
(time_value.hour * 60) + time_value.min
|
||
end
|
||
end
|