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 retrievedefault_on_missing(mixed, optional): Value to return if key is not found
Returns:
- The cached value if found
default_on_missingif key not found and default providednilif key not found and no default provided
Example:
-- 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")
endcache.put(key, value)
Stores a value in the cache with the specified key.
Parameters:
key(string): The cache key to store undervalue(mixed): The value to cache (strings, numbers, booleans, tables)
Returns:
trueif successfulfalseif failed
Example:
-- 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")
endcache.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 undervalue(mixed): The value to cachettl_seconds(number): Time to live in seconds (supports fractional seconds)
Returns:
trueif successfulfalseif failed
Example:
-- 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 code - setting cache prefix
LuaEngine.run_main_function(lua_state, args, %{cache_prefix: "tenant_123"})Example with Prefixes:
-- 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:
cache.put("string_key", "Hello World")
cache.put("number_key", 42.5)
cache.put("boolean_key", true)
cache.put("nil_key", nil) -- Stores nil explicitlyComplex Types:
-- 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
Use descriptive keys: Include entity type and ID for clarity
luacache.put("user:123:profile", user_data) cache.put("session:abc123:data", session_info)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)Handle cache misses gracefully:
lualocal 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) endUse prefixes for isolation:
lua-- Different environments/tenants should use different prefixes -- This is handled automatically via priv_data configuration
Integration Examples
Caching API Responses
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
endSession Management
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
endRate Limiting
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")
endSecurity 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)