Redis-based caching system (internal/utils/cache/).
Related Documentation:
- Stream Operations - Pub/sub streaming patterns
- Database Operations - Cache-aside pattern for DB results
- Generic Types - Type-safe cache operations
All cache helpers accept logical names and apply the configured Redis prefix internally.
By default the daemon uses plugin_daemon, and operators can override it with
REDIS_KEY_PREFIX.
// Store and retrieve
cache.Store("key", value, time.Minute*30)
val, err := cache.Get[Type]("key")
cache.Del("key")
// Check existence
exists, _ := cache.Exist("key")For cluster state management:
// Set map field
cache.SetMapOneField(CLUSTER_STATUS_KEY, nodeId, nodeStatus)
// Get single field
node, err := cache.GetMapField[node](CLUSTER_STATUS_KEY, nodeId)
// Get entire map
nodes, err := cache.GetMap[node](CLUSTER_STATUS_KEY)
// Delete field
cache.DelMapField(CLUSTER_STATUS_KEY, nodeId)Pub/sub channels are prefixed with the same REDIS_KEY_PREFIX value as keys, so
callers should always pass logical channel names.
// Publish event
cache.Publish(CHANNEL, event)
// Subscribe to channel
eventChan, cancel := cache.Subscribe[EventType](CHANNEL)
defer cancel()
for event := range eventChan {
// Process event
}// Acquire lock with timeout
acquired := cache.Lock(key, duration, timeout)
if acquired {
defer cache.Unlock(key)
// Critical section
}The AcquireOwnedLock function provides token-based lock ownership with advanced features:
// Acquire lock with timeout
lock, err := cache.AcquireOwnedLock(key, expire, tryLockTimeout)
if err == cache.ErrLockTimeout {
// Lock acquisition timed out
return err
}
if err != nil {
return err
}
defer lock.Unlock()
// Critical sectionThe OwnedLock type supports:
Renewal: Extend lock expiration while holding it
if err := lock.Renew(time.Minute); err == cache.ErrLockNotOwned {
// Lock was lost
}Keep-Alive: Automatic periodic renewal
ctx, cancel := context.WithCancel(context.Background())
defer cancel()
errCh := lock.KeepAlive(ctx, time.Minute)
// Lock is renewed every expire/3 interval
// Cancel context to stop keep-alive
if err := <-errCh; err != nil {
// Keep-alive failed (lock lost or error)
}Safe Unlock: Only the lock owner can unlock
if err := lock.Unlock(); err == cache.ErrLockNotOwned {
// Lock expired or was never owned
}The OwnedLock mechanism uses unique tokens to ensure only the lock owner can renew or release the lock, preventing accidental releases by other processes.
Error Constants:
ErrLockTimeout: Lock acquisition timed outErrLockNotOwned: Returned when attempting to renew or unlock a lock that is not ownedErrInvalidLockExpiration: Returned when lock expiration duration is not positive
Helper functions in redis_auto_type.go:
// Get with automatic getter fallback
value := cache.AutoGetWithGetter(key, func() (*Type, error) {
return fetchFromDB()
}, ttl)
// Auto delete
cache.AutoDelete[Type](key)// Store session
sessionKey := fmt.Sprintf("session_info:%s", id)
cache.Store(sessionKey, session, time.Minute*30)
// Retrieve session
session, err := cache.Get[Session](sessionKey)
if err == cache.ErrNotFound {
// Session expired or not found
}Initialize Redis client in main:
cache.InitRedisClient(
addr, // "localhost:6379"
cache.RedisCredentials{
Username: username, // optional
Password: password,
CredentialProvider: nil, // optional StreamingCredentialsProvider
},
useSsl, // bool
db, // database number
nil, // *tls.Config (optional)
)Azure Entra ID authentication is supported via the REDIS_USE_AZURE_MANAGED_IDENTITY environment variable. When enabled, it uses DefaultAzureCredential for token-based authentication instead of static username/password credentials.
Important: Azure Managed Redis only supports database 0, so REDIS_DB must be set to 0 when using this feature.
// Create Azure credentials provider
provider, err := cache.NewAzureEntraIDCredentialsProvider()
if err != nil {
log.Fatal("failed to create Azure credentials provider:", err)
}
cache.InitRedisClient(
addr,
cache.RedisCredentials{
CredentialProvider: provider, // takes precedence over Username/Password
},
useSsl,
db,
nil,
)When CredentialProvider is set, it takes precedence over static Username and Password fields.
REDIS_KEY_PREFIXdefaults toplugin_daemon- applies to keys and pub/sub channels managed by this package
- changing the prefix switches the active Redis namespace and does not migrate old data
- logical keys that contain Redis Cluster hash tags such as
{remote:key:manager}keep those tags intact because the prefix is prepended to the full logical key