# frozen_string_literal: true require "concurrent/timer_task" require "caddy/version" require "caddy/task_observer" require "caddy/cache" # Caddy gives you a auto-updating global cache to speed up requests module Caddy class << self # @!attribute error_handler # @return [Proc] called when any cache refresher throws an exception (or times out) attr_accessor :error_handler # see {#logger} attr_writer :logger end @started_pid = nil @caches = Hash.new { |h, k| h[k] = Caddy::Cache.new(k) } @needs_fork_check = !Concurrent::TimerSet.private_method_defined?(:ns_reset_if_forked) # Returns the cache object at a key. # # If the cache at +k+ does not exist yet, Caddy will initialize an empty one. # # @param k [Symbol] the cache key. # @return [Caddy::Cache] the cache object at key +k+. def self.[](k) @caches[k] end # Starts the Caddy refresh processes for all caches. # # If the refresh process was started pre-fork, Caddy will error out, as this means # the refresh process would have been killed by the fork. # # Caddy freezes the hash of caches at this point, so no more further caches can be # added after start. def self.start raise_if_forked if @needs_fork_check logger.info "Starting Caddy with refreshers: #{@caches.keys.join(', ')}" @caches.values.each(&:start).all? end # Cleanly shut down all currently running refreshers. def self.stop logger.info "Stopping Caddy refreshers" @caches.values.each(&:stop).all? end # Start and then stop all refreshers. Useful for triggering an immediate refresh of all caches. def self.restart stop start end # @!attribute logger # @return [Logger] logger used for all non-fatals; defaults to the Rails logger if it exists def self.logger @logger ||= begin if defined?(Rails.logger) Rails.logger else @logger ||= Logger.new(STDOUT).tap do |logger| logger.formatter = -> (_, datetime, _, msg) { "#{datetime}: #{msg}\n" } end end end end # TODO: when https://github.com/ruby-concurrency/concurrent-ruby/pull/573 is merged, remove this whole block # or add a warning # @private def self.raise_if_forked if !@started_pid @started_pid = $$ elsif @started_pid && $$ != @started_pid raise "Please run `Caddy.start` *after* forking, as the refresh thread will get killed after fork" end end end