setler
setler copied to clipboard
Is it possible to cache application level settings?
Would be nice if the "thing id" = null's out there that are generally application level settings were somehow cacheable to avoid invoking a query every time the setting needed to be checked.
Starts to add up after a while in a high traffic app especially if there are multiple settings per page. Is there any way to do that currently? I didn't see it in the README.
This is not something that Setler does currently, but it would be a nice feature to have.
I set this up on my application in the Settings class which was extending Setler. You could roll a lot of this into Setler itself fairly easily. Also, make sure that this is turned off during tests. I wasn't sure how to do per-request detection from a model so there is a very rigged up solution in the code instead.
class Settings < Setler::Settings
cattr_accessor :last_cleared_at, :expire_checked_at, :expired_at, :cache_settings, :cache_values
@cache_settings = nil
@cache_values = {}
# Get and Set variables when the calling method is the variable name
def self.[](var)
return super(var) unless self.cache_enabled?
self.clear_cache if self.clear_cache?
@cache_values[var.to_s] = super(var) unless @cache_values.has_key?(var.to_s)
@cache_values[var.to_s]
end
def self.[]=(var, value)
response = super(var,value)
if self.cache_enabled?
self.expire_central_cache
self.clear_cache
end
response
end
def self.cache_enabled?
@cache_settings = Myapp::Application.config.settings_cache_enabled if @cache_settings.nil?
@cache_settings == true
end
def self.expire_central_cache
# Class/instance variables are stored in RAM on a per-dyno/server basis
# This centrally notifies them to update local caches
Rails.cache.write(:settings_cache_expired_at,Time.now.utc)
end
def self.central_cache_expired_at
if @expire_checked_at.nil? || @expire_checked_at <= 1.second.ago
# This is a poor man's per-request cache
# Without this, we still hit Rails.cache on each check which can incur network latency depending on the cache
@expired_at = Rails.cache.read(:settings_cache_expired_at)
@expire_checked_at = Time.now.utc
end
@expired_at
end
def self.clear_cache?
@last_cleared_at ||= Time.now.utc
updated_at = self.central_cache_expired_at
!(updated_at.nil? || updated_at < @last_cleared_at)
end
def self.clear_cache
@cache_values = {}
@last_cleared_at = Time.now.utc
end
end