Skip to content
/ cachex Public

A powerful caching library for Elixir with support for transactions, fallbacks and expirations

License

Notifications You must be signed in to change notification settings

whitfin/cachex

Repository files navigation

Cachex

Build Status Coverage Status Hex.pm Version Documentation

Cachex is an extremely fast in-memory key/value store with support for many useful features:

  • Time-based key expirations
  • Maximum size protection
  • Pre/post execution hooks
  • Proactive/reactive cache warming
  • Transactions and row locking
  • Asynchronous write operations
  • Distribution across app nodes
  • Syncing to a local filesystem
  • Idiomatic cache streaming
  • Batched write operations
  • User command invocation
  • Statistics gathering

All of these features are optional and are off by default so you can pick and choose those you wish to enable.

Setting Up

To get started, please add Cachex to your mix.exs list of dependencies and then pull it using mix deps.get:

def deps do
  [{:cachex, "~> 4.0"}]
end

Depending on what you're trying to do, there are a couple of different ways you might want to go about starting a cache. If you're testing out Cachex inside iex, you can call Cachex.start_link/2 manually:

Cachex.start_link(:my_cache)     # with default options
Cachex.start_link(:my_cache, []) # with custom options

In other cases, you might want to start a cache within an existing supervision tree. If you created your project via mix with the --sup flag, this should be available to you inside lib/my_app/application.ex:

children = [
  {Cachex, [:my_cache]},     # with default options
  {Cachex, [:my_cache, []]}  # with custom options
]

Both of these approaches work the same way; your options are parsed and your cache is started as a child under the appropriate parent process. The latter is recommended for production applications, as it will ensure your cache is managed correctly inside your application.

Basic Examples

Working with a cache is pretty straightforward, and basically everything is provided by the core Cachex module. You can make calls to a cache using the name you registered it under at startup time.

Let's take a quick look at some basic calls you can make to a cache in a quick iex session:

# create a default cache in our shell session
{:ok, _pid} = Cachex.start_link(:my_cache)

# place a "my_value" string against the key "my_key"
{:ok, true} = Cachex.put(:my_cache, "my_key", "my_value")

# verify that the key exists under the key name
{:ok, true} = Cachex.exists?(:my_cache, "my_key")

# verify that "my_value" is returned when we retrieve
{:ok, "my_value"} = Cachex.get(:my_cache, "my_key")

# remove the "my_key" key from the cache
{:ok, true} = Cachex.del(:my_cache, "my_key")

# verify that the key no longer exists
{:ok, false} = Cachex.exists?(:my_cache, "my_key")

# verify that "my_value" is no longer returned
{:ok, nil} = Cachex.get(:my_cache, "my_key")

It's worth noting here that the actions supported by the Cachex API have an automatically generated "unsafe" equivalent (i.e. appended with !). These options will unpack the returned tuple, and return values directly:

# calling by default will return a tuple
{:ok, nil} = Cachex.get(:my_cache, "key")

# calling with `!` unpacks the tuple
nil = Cachex.get!(:my_cache, "key")

# causing an error will return an error tuple value
{:error, :no_cache} =  Cachex.get(:missing_cache, "key")

# but calling with `!` raises the error
Cachex.get!(:missing_cache, "key")
** (Cachex.Error) Specified cache not running
    (cachex) lib/cachex.ex:249: Cachex.get!/3

The ! version of functions exists for convenience, in particular to make chaining and assertions easier in unit testing. For production use cases it's recommended to avoid ! wrappers, and instead explicitly handle th