ExCache

ExCache is a simple, yet powerful caching framework for Elixir applications. It provides a fast, in-memory caching solution with TTL (Time To Live) support, comprehensive statistics, and a clean, idiomatic API.

Features

Installation

Add ex_cache to your list of dependencies in mix.exs:

def deps do
  [
    {:ex_cache, "~> 0.2.0"}
  ]
end

Then run mix deps.get to install the dependency.

Usage

Basic Usage

# Start a cache process
{:ok, pid} = ExCache.Ets.start_link(:my_cache)

# Store a value
:ok = ExCache.Ets.put(:my_cache, :user_123, %{name: "John", email: "john@example.com"})

# Retrieve a value
user = ExCache.Ets.get(:my_cache, :user_123)
# => %{name: "John", email: "john@example.com"}

# Store with TTL (in milliseconds)
:ok = ExCache.Ets.put(:my_cache, :session_token, "abc123", ttl: 3600000)  # 1 hour

# Delete a value
:ok = ExCache.Ets.del(:my_cache, :user_123)

Using Fetch with Fallback

The fetch/4 function provides a powerful pattern for retrieving values with fallback logic:

# Fetch with automatic caching of computed value
user = ExCache.Ets.fetch(:my_cache, :user_456, [ttl: 300000], fn user_id ->
  # This function is only called if the key is not in cache
  {:commit, Database.get_user(user_id)}  # Store the result in cache
end)

# Fetch without caching (ignore pattern)
config = ExCache.Ets.fetch(:my_cache, :app_config, [], fn key ->
  {:ignore, File.read!("config/#{key}.json")}  # Return without storing
end)

Supervisor Integration

ExCache is designed to work seamlessly with OTP supervisors:

defmodule MyApp.Application do
  use Application

  def start(_type, _args) do
    children = [
      {ExCache.Ets, name: :my_cache},
      # ... other children
    ]

    opts = [strategy: :one_for_one, name: MyApp.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

Cache Statistics

Monitor cache performance with built-in statistics:

# Get current statistics
stats = ExCache.Ets.stats(:my_cache)
# => %{
#   hits: 1250,
#   misses: 42,
#   puts: 1320,
#   deletes: 89,
#   total_operations: 2701
# }

# Calculate hit rate
hit_rate = stats.hits / (stats.hits + stats.misses)
# => 0.9675 (96.75% hit rate)

# Reset statistics when needed
:ok = ExCache.Ets.reset_stats(:my_cache)

Manual Cleanup

While ExCache automatically cleans up expired entries, you can also trigger manual cleanup:

# Manually clean up expired entries
{:ok, deleted_count} = ExCache.Ets.cleanup_expired(:my_cache)
IO.puts("Cleaned up #{deleted_count} expired entries")

API Reference

Core Functions

put(name, key, value, opts \\ [])

Store a key-value pair in the cache.

get(name, key)

Retrieve a value from the cache.

del(name, key)

Delete a key-value pair from the cache.

Advanced Functions

fetch(name, key, opts \\ [], fallback)

Retrieve a value with fallback functionality.

Statistics Functions

stats(name)

Get cache statistics.

reset_stats(name)

Reset all cache statistics to zero.

Maintenance Functions

cleanup_expired(name)

Manually clean up expired entries.

Configuration

Cache Process Configuration

The cache process uses a timeout of 5000 milliseconds for automatic cleanup of expired entries. This is currently not configurable but provides a good balance between cleanup frequency and performance.

TTL Management

Error Handling

ExCache gracefully handles various edge cases:

Performance Considerations

Memory Usage

ExCache uses ETS tables for storage, which are kept in memory. Monitor memory usage when caching large amounts of data.

Automatic Cleanup

Expired entries are automatically cleaned up every 5 seconds. This process is efficient and doesn’t block normal operations.

Concurrency

The cache is designed for high concurrency with minimal contention between operations. All read operations are synchronous, while write operations are asynchronous.

Testing

Run the test suite:

mix test

Include property tests:

mix test test/ex_cache_property_test.exs

Contributing

We welcome contributions! Please see our Contributing Guidelines for details.

Development Setup

  1. Fork the repository
  2. Clone your fork: git clone https://github.com/your-username/ex_cache.git
  3. Create your feature branch: git checkout -b feature/amazing-feature
  4. Install dependencies: mix deps.get
  5. Run tests: mix test
  6. Commit your changes: git commit -m 'Add amazing feature'
  7. Push to the branch: git push origin feature/amazing-feature
  8. Open a Pull Request

Code Style

License

ExCache is released under the MIT License.

Changelog

v0.2.0 (2024-01-XX)

Added

Changed

Fixed

v0.1.1 (2024-01-XX)