Skip to content
This repository has been archived by the owner on May 10, 2019. It is now read-only.
/ cache_reduce Public archive

A simple, powerful pattern for caching data

License

Notifications You must be signed in to change notification settings

ankane/cache_reduce

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 

History

9 Commits
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

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:

About

A simple, powerful pattern for caching data

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages