title: Rails cache counter
body: <p>I have a simple Ruby method meant to throttle some execution.</p>
  
  <pre><code>MAX_REQUESTS = 60
  # per
  TIME_WINDOW = 1.minute
  
  def throttle
    cache_key = "#{request.ip}_count"
    count = Rails.cache.fetch(cache_key, expires_in: TIME_WINDOW.to_i) { 0 }
  
    if count.to_i &gt;= MAX_REQUESTS
      render json: { message: 'Too many requests.' }, status: 429
      return
    end
    Rails.cache.increment(cache_key)
    true
  end
  </code></pre>
  
  <p>After some testing I've found that <code>cache_key</code> never invalidates.</p>
  
  <p>I investigated with <code>binding.pry</code> and found the issue:</p>
  
  <pre><code>[35] pry(#&lt;Refinery::ApiReferences::Admin::ApiHostsController&gt;)&gt; Rails.cache.write(cache_key, count += 1, expires_in: 60, raw: true)
  =&gt; true
  [36] pry(#&lt;Refinery::ApiReferences::Admin::ApiHostsController&gt;)&gt; Rails.cache.send(:read_entry, cache_key, {})
  =&gt; #&lt;ActiveSupport::Cache::Entry:0x007fff1e34c978 @created_at=1495736935.0091069, @expires_in=60.0, @value=11&gt;
  [37] pry(#&lt;Refinery::ApiReferences::Admin::ApiHostsController&gt;)&gt; Rails.cache.increment(cache_key)
  =&gt; 12
  [38] pry(#&lt;Refinery::ApiReferences::Admin::ApiHostsController&gt;)&gt; Rails.cache.send(:read_entry, cache_key, {})
  =&gt; #&lt;ActiveSupport::Cache::Entry:0x007fff1ee105a8 @created_at=1495736965.540865, @expires_in=nil, @value=12&gt;
  </code></pre>
  
  <p>So, <code>increment</code> is wiping out the <code>expires_in</code> value and changing the <code>created_at</code>, regular writes will do the same thing. </p>
  
  <p>How do I prevent this? I just want to update the <em>value</em> for a given cache key.</p>
  
  <p><strong>UPDATE</strong></p>
  
  <p>Per suggestion I tried:</p>
  
  <pre><code>MAX_REQUESTS = 60
  # per
  TIME_WINDOW = 1.minute
  
  def throttle
    cache_key = "#{request.ip}_count"
    count = Rails.cache.fetch(cache_key, expires_in: TIME_WINDOW.to_i, raw: true) { 0 }
  
    if count.to_i &gt;= MAX_REQUESTS
      render json: { message: 'Too many requests.' }, status: 429
      return
    end
    Rails.cache.increment(cache_key)
    true
  end
  </code></pre>
  
  <p>No effect. Cache does not expire.</p>