lib/config_skeleton.rb in config_skeleton-2.0.0 vs lib/config_skeleton.rb in config_skeleton-2.1.0

- old
+ new

@@ -205,15 +205,19 @@ # def self.watches @watches || [] end - def initialize(*_) + def initialize(*_, metrics:, config:) super initialize_config_skeleton_metrics @trigger_regen_r, @trigger_regen_w = IO.pipe @terminate_r, @terminate_w = IO.pipe + + raise "cooldown_duration invalid" if cooldown_duration < 0 + raise "sleep_duration invalid" if sleep_duration < 0 + raise "sleep_duration must not be less than cooldown_duration" if sleep_duration < cooldown_duration end # Expose the write pipe which can be written to to trigger a config # regeneration with a forced reload; a similar mechanism is used for # shutdown but in that case writes are managed internally. @@ -240,15 +244,20 @@ watch(*self.class.watches) logger.debug(logloc) { "notifier fd is #{notifier.to_io.inspect}" } loop do - if ios = IO.select( - [notifier.to_io, @terminate_r, @trigger_regen_r], - [], [], - sleep_duration.tap { |d| logger.debug(logloc) { "Sleeping for #{d} seconds" } } - ) + if cooldown_duration > 0 + logger.debug(logloc) { "Sleeping for #{cooldown_duration} seconds (cooldown)" } + IO.select([@terminate_r], [], [], cooldown_duration) + end + + timeout = sleep_duration - cooldown_duration + logger.debug(logloc) { "Sleeping for #{timeout} seconds unless interrupted" } + ios = IO.select([notifier.to_io, @terminate_r, @trigger_regen_r], [], [], timeout) + + if ios if ios.first.include?(notifier.to_io) logger.debug(logloc) { "inotify triggered" } notifier.process regenerate_config(force_reload: true) elsif ios.first.include?(@terminate_r) @@ -442,9 +451,28 @@ # @return [Integer] the number of seconds to sleep for. This *must not* be # negative, lest you create a tear in the space-time continuum. # def sleep_duration 60 + end + + # How long to ignore signals/notifications after a config regeneration + # + # Hammering a downstream service with reload requests is often a bad idea. + # This method exists to allow subclasses to define a 'cooldown' duration. + # After each config regeneration, the config generator will sleep for this + # duration, regardless of any CONT signals or inotify events. Those events + # will be queued up, and processed at the end of the cooldown. + # + # The cooldown_duration is counted as part of the sleep_duration. So for + # the default values of 60 and 5, the service will cooldown for 5s, then wait + # for 55s. + # + # @return [Integer] the number of seconds to 'cooldown' for. This *must* be + # greater than zero, and less than sleep_duration + # + def cooldown_duration + 5 end # The instance of INotify::Notifier that is holding our file watches. # # @return [INotify::Notifier]