iachat/enterprise/app/services/captain/lifecycle/guards/quiet_hours.rb
Rodribm10 fcdc2054b5 feat(lifecycle): add QuietHours guard with 2h staleness limit
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-04-15 01:44:39 -03:00

53 lines
1.5 KiB
Ruby
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# 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:0018:00)
cur_min >= from_min && cur_min < to_min
else
# Crosses midnight (e.g. 23:0008: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