Class: Caddy::Cache
- Inherits:
-
Object
- Object
- Caddy::Cache
- Defined in:
- lib/caddy/cache.rb
Constant Summary collapse
- DEFAULT_REFRESH_INTERVAL =
Default refresh interval, in seconds
60
- REFRESH_INTERVAL_JITTER_PCT =
Percentage to randomly smooth the refresh interval to avoid stampeding herd on expiration
0.15
Instance Attribute Summary collapse
-
#error_handler ⇒ Proc
called when exceptions or timeouts happen within the refresher.
-
#refresh_interval ⇒ Numeric
Number of seconds between calls to #refresher; timeout is set to
{#refresher} - 0.1
. -
#refresher ⇒ Proc
Called on interval #refresh_interval with the returned object used as the cache.
Instance Method Summary collapse
-
#[](k) ⇒ Object
Convenience method for getting the value of the refresher-returned object at path
k
, assuming the refresher-returned value responds to[]
. -
#cache ⇒ Object
Returns the refresher-produced value that is used as the cache.
-
#initialize(key) ⇒ Cache
constructor
Create a new periodically updated cache.
-
#refresh ⇒ Object
Updates the internal cache object.
-
#start ⇒ Object
Starts the period refresh cycle.
-
#stop ⇒ Object
Stops the current executing refresher.
Constructor Details
#initialize(key) ⇒ Cache
Create a new periodically updated cache.
25 26 27 28 29 30 |
# File 'lib/caddy/cache.rb', line 25 def initialize(key) @task = nil @refresh_interval = DEFAULT_REFRESH_INTERVAL @cache = nil @key = key end |
Instance Attribute Details
#error_handler ⇒ Proc
called when exceptions or timeouts happen within the refresher
21 22 23 |
# File 'lib/caddy/cache.rb', line 21 def error_handler @error_handler end |
#refresh_interval ⇒ Numeric
Returns number of seconds between calls to #refresher; timeout is set to {#refresher} - 0.1
.
16 17 18 |
# File 'lib/caddy/cache.rb', line 16 def refresh_interval @refresh_interval end |
#refresher ⇒ Proc
Returns called on interval #refresh_interval with the returned object used as the cache.
12 13 14 |
# File 'lib/caddy/cache.rb', line 12 def refresher @refresher end |
Instance Method Details
#[](k) ⇒ Object
Convenience method for getting the value of the refresher-returned object at path k
, assuming the refresher-returned value responds to []
.
If not, #cache can be used instead to access the refresher-returned object.
37 38 39 |
# File 'lib/caddy/cache.rb', line 37 def [](k) cache[k] end |
#cache ⇒ Object
Returns the refresher-produced value that is used as the cache.
42 43 44 45 46 47 48 49 50 51 52 |
# File 'lib/caddy/cache.rb', line 42 def cache raise "Please run `Caddy.start` before attempting to access the cache" unless @task && @task.running? unless @cache logger.warn "Caddy cache access of :#{@key} before initial load; doing synchronous load."\ "Please allow some more time for your app to start up." refresh end @cache end |
#refresh ⇒ Object
Updates the internal cache object.
Freezes the result to avoid mutation errors.
101 102 103 |
# File 'lib/caddy/cache.rb', line 101 def refresh @cache = refresher.call.freeze end |
#start ⇒ Object
Starts the period refresh cycle.
Every refresh_interval
seconds – smoothed by a jitter amount (a random amount +/- REFRESH_INTERVAL_JITTER_PCT
) – the refresher lambda is called and the results stored in cache
.
Note that the result of the refresh is frozen to avoid multithreading mutations.
60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 |
# File 'lib/caddy/cache.rb', line 60 def start unless refresher && refresher.respond_to?(:call) raise "Please set your cache refresher via `Caddy[:#{@key}].refresher = -> { <code that returns a value> }`" end raise "`Caddy[:#{@key}].refresh_interval` must be > 0" unless refresh_interval > 0 jitter_amount = [0.1, refresh_interval * REFRESH_INTERVAL_JITTER_PCT].max interval = refresh_interval + rand(-jitter_amount...jitter_amount) timeout_interval = [interval - 1, 0.1].max stop # stop any existing task from running @task = Concurrent::TimerTask.new( run_now: true, execution_interval: interval, timeout_interval: timeout_interval ) do refresh nil # no need for the {#Concurrent::TimerTask} to keep a reference to the value end @task.add_observer(Caddy::TaskObserver.new(error_handler, @key)) logger.debug "Starting Caddy refresher for :#{@key}, updating every #{interval.round(1)}s." @task.execute @task.running? end |
#stop ⇒ Object
Stops the current executing refresher.
The current cache value is persisted even if the task is stopped.
94 95 96 |
# File 'lib/caddy/cache.rb', line 94 def stop @task.shutdown if @task && @task.running? end |