Skip to content

Cache Module

The cache module provides distributed caching functionality with TTL (time-to-live) support and prefix-based isolation. It uses Cachex as the underlying cache store and supports cache prefixes for multi-tenant or namespace separation.

Functions

cache.get(key, default_on_missing)

Retrieves a value from the cache by key.

Parameters:

  • key (string): The cache key to retrieve
  • default_on_missing (mixed, optional): Value to return if key is not found

Returns:

  • The cached value if found
  • default_on_missing if key not found and default provided
  • nil if key not found and no default provided

Example:

lua
-- Get with default value
local user_name = cache.get("user:123:name", "Unknown User")

-- Get without default (returns nil if not found)
local session_data = cache.get("session:abc123")

if session_data then
    print("Session found: " .. session_data.user_id)
else
    print("Session expired or not found")
end

cache.put(key, value)

Stores a value in the cache with the specified key.

Parameters:

  • key (string): The cache key to store under
  • value (mixed): The value to cache (strings, numbers, booleans, tables)

Returns:

  • true if successful
  • false if failed

Example:

lua
-- Store simple values
local success = cache.put("user:123:name", "John Doe")

-- Store complex data structures
local user_data = {
    id = 123,
    name = "John Doe",
    email = "john@example.com",
    preferences = {
        theme = "dark",
        language = "en"
    },
    roles = {"user", "admin"}
}

local success = cache.put("user:123:profile", user_data)

if success then
    print("User data cached successfully")
end

cache.put_ttl(key, value, ttl_seconds)

Stores a value in the cache with a TTL (time-to-live).

Parameters:

  • key (string): The cache key to store under
  • value (mixed): The value to cache
  • ttl_seconds (number): Time to live in seconds (supports fractional seconds)

Returns:

  • true if successful
  • false if failed

Example:

lua
-- Cache session data for 1 hour
local session_data = {user_id = 123, token = "abc123"}
cache.put_ttl("session:abc123", session_data, 3600)

-- Cache API response for 5 minutes
local api_response = {data = "...", timestamp = os.time()}
cache.put_ttl("api:users:list", api_response, 300)

-- Cache temporary data for 30 seconds
cache.put_ttl("temp:calculation:xyz", result, 30)

-- Fractional TTL (1.5 seconds)
cache.put_ttl("very_short_cache", "temporary", 1.5)

Cache Prefix Isolation

The cache module supports prefix-based isolation through the :cache_prefix private state. This allows different scripts, tenants, or namespaces to maintain separate cache spaces.

Setting Cache Prefix: The cache prefix is set via the priv_data parameter when running Lua functions:

elixir
# Elixir code - setting cache prefix
LuaEngine.run_main_function(lua_state, args, %{cache_prefix: "tenant_123"})

Example with Prefixes:

lua
-- Script running with cache_prefix: "tenant_123"
cache.put("user_count", 150)
local count = cache.get("user_count")  -- Returns 150

-- Script running with cache_prefix: "tenant_456"
cache.put("user_count", 300)
local count = cache.get("user_count")  -- Returns 300

-- The two values are completely isolated due to different prefixes
-- Internal keys become: "tenant_123:user_count" and "tenant_456:user_count"

Data Type Support

The cache module supports all Lua data types:

Primitive Types:

lua
cache.put("string_key", "Hello World")
cache.put("number_key", 42.5)
cache.put("boolean_key", true)
cache.put("nil_key", nil)  -- Stores nil explicitly

Complex Types:

lua
-- Arrays
cache.put("tags", {"admin", "user", "editor"})

-- Objects/Tables
cache.put("config", {
    debug = true,
    max_users = 1000,
    features = {"feature_a", "feature_b"}
})

-- Nested structures
cache.put("app_state", {
    users = {
        {id = 1, name = "Alice"},
        {id = 2, name = "Bob"}
    },
    settings = {
        theme = "dark",
        notifications = {
            email = true,
            sms = false
        }
    }
})

Best Practices

  1. Use descriptive keys: Include entity type and ID for clarity

    lua
    cache.put("user:123:profile", user_data)
    cache.put("session:abc123:data", session_info)
  2. Set appropriate TTLs: Don't cache forever unless necessary

    lua
    -- Short-lived data
    cache.put_ttl("api:rate_limit:user123", current_count, 60)
    
    -- Medium-lived data
    cache.put_ttl("user:123:permissions", permissions, 3600)
    
    -- Long-lived but not permanent
    cache.put_ttl("app:config", config_data, 86400)
  3. Handle cache misses gracefully:

    lua
    local user_data = cache.get("user:123:profile")
    if not user_data then
        -- Fetch from database or API
        user_data = fetch_user_profile(123)
        -- Cache for future use
        cache.put_ttl("user:123:profile", user_data, 1800)
    end
  4. Use prefixes for isolation:

    lua
    -- Different environments/tenants should use different prefixes
    -- This is handled automatically via priv_data configuration

Integration Examples

Caching API Responses

lua
function fetch_user_list()
    local cached = cache.get("api:users:list")
    if cached then
        print("Returning cached user list")
        return cached
    end

    -- Fetch from API
    local response = http.request({
        method = "get",
        url = "https://api.example.com/users",
        headers = {Authorization = "Bearer " .. api_token}
    })

    if response.success then
        -- Cache for 5 minutes
        cache.put_ttl("api:users:list", response.data.body, 300)
        return response.data.body
    end

    return nil
end

Session Management

lua
function create_session(user_id)
    local session_id = generate_session_id()
    local session_data = {
        user_id = user_id,
        created_at = os.time(),
        last_activity = os.time()
    }

    -- Cache session for 24 hours
    local success = cache.put_ttl("session:" .. session_id, session_data, 86400)

    if success then
        return session_id
    else
        return nil
    end
end

function get_session(session_id)
    return cache.get("session:" .. session_id)
end

function invalidate_session(session_id)
    -- Note: Cachex doesn't expose delete via this API,
    -- but TTL expiration handles cleanup
    return true
end

Rate Limiting

lua
function check_rate_limit(user_id, limit, window_seconds)
    local key = "rate_limit:" .. user_id
    local current = cache.get(key, 0)

    if current >= limit then
        return false  -- Rate limit exceeded
    end

    -- Increment counter
    cache.put_ttl(key, current + 1, window_seconds)
    return true  -- Request allowed
end

-- Usage
if check_rate_limit("user123", 100, 3600) then
    -- Process request
    print("Request allowed")
else
    print("Rate limit exceeded")
end

Security and Performance

Security:

  • No special permissions required (caching is a performance optimization)
  • Cache isolation prevents cross-contamination between prefixes
  • TTL ensures data doesn't persist indefinitely

Performance:

  • Distributed cache provides high performance across cluster nodes
  • Automatic cleanup via TTL prevents memory leaks
  • Configurable cache size limits (50,000 entries by default)

Connect. Combine. Collaborate.
The pioneering open integration platform, dedicated to transforming connectivity in the printing industry.