Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Is it possible to cache application level settings? #19

Open
brightball opened this issue Jul 18, 2012 · 2 comments
Open

Is it possible to cache application level settings? #19

brightball opened this issue Jul 18, 2012 · 2 comments

Comments

@brightball
Copy link

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.

@ckdake
Copy link
Owner

ckdake commented Jul 18, 2012

This is not something that Setler does currently, but it would be a nice feature to have.

@brightball
Copy link
Author

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

@brightball brightball reopened this Dec 5, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants