A simple, powerful pattern for caching data
Branch: master
Clone or download
Fetching latest commit…
Cannot retrieve the latest commit at this time.
Permalink
Type Name Latest commit message Commit time
Failed to load latest commit information.
lib
.gitignore
Gemfile
LICENSE.txt
README.md
Rakefile
cache_reduce.gemspec

README.md

CacheReduce

A simple, powerful pattern for caching data

⚠️ Work in progress - interface not finalized

How It Works

  1. Cache step - data is cached in small buckets by time
  • Break time range into small buckets
  • Get cached values
  • Caclulate uncached values
  • Cache uncached values, except the current period
  1. Reduce step - group buckets and reduce

Results are cached automatically - no need to precompute values (the exact same method to query can be used to preheat the cache if necessary).

Since the current period is always calculated, results are real-time. 💥

Examples

Searches

class SearchesCount
  include CacheReduce::Magic

  def value(time_range)
    Search.where(created_at: time_range).count
  end
end

Count all searches

SearchesCount.all(time_range: time_range)

Count searches by day

SearchesCount.by_day(time_range: time_range)

New Users

Use the preload method for faster cache warming.

class NewUsersCount
  include CacheReduce::Magic

  def preload(time_range)
    @users = User.group_by_hour(:created_at, range: time_range).count
  end

  def value(time_range)
    @users[time_range.first]
  end
end

And:

NewUsersCount.all(time_range: time_range)
NewUsersCount.by_day(time_range: time_range)

Visitors

Reduce ids instead of numbers - great for creating funnels

class VisitorIds
  include CacheReduce::Magic

  def value(time_range)
    Visit.where(created_at: time_range).uniq.pluck(:user_id)
  end

  def reduce(values)
    values.flatten
  end
end

Events

Pass your own arguments

class EventCount
  include CacheReduce::Magic

  def initialize(name)
    @name = name
  end

  def key
    ["event", @name]
  end

  def value(time_range)
    Ahoy::Event.where(name: @name, time: time_range).count
  end

end

Reducers

Built-in methods

  • all
  • by_hour
  • by_day
  • by_week
  • by_month
  • by_year

Built-in operations

  • sum
  • flatten

Installation

Add this line to your application’s Gemfile:

gem 'cache_reduce'

Reference

Force recache [master]

SearchesCount.all(time_range: time_range, recache: true)

TODO

  • more reducer methods - by_week, by_month, etc.
  • custom cache period, not just hours
  • more data stores
  • better interface
  • better readme

Contributing

Everyone is encouraged to help improve this project. Here are a few ways you can help: