ctxcache is a strongly-typed, context-scoped cache package designed for request-scoped data.
ctxcache attaches a concurrency-safe, write-once key-value store to context.Context, allowing values to be
implicitly propagated across call boundaries without polluting function signatures.
- Strong Type Safety: Uses generics combining string names and Go type parameters as key identifiers, ensuring type safety and preventing collisions between values of different types—even if they share the same string identifier
- Concurrency Safe: Internally uses mutex-protected maps, supporting concurrent access
- Write-Once Semantics: Each key can be assigned exactly once, then read multiple times until the cache is cleared
- Context Lifecycle: Cache lifecycle is explicitly controlled by the cancel function returned from
Init - Request Scope Isolation: Cache is attached to context, naturally supporting request-level data isolation
Use the Init function to attach a cache to a context:
ctx, cancel := ctxcache.Init(ctx)
defer cancel() // Clean up cache at request boundaryInit is idempotent: repeated calls with the same context return the original context and a no-op cancel function.
Use the Set function to assign a value to a key:
err := ctxcache.Set(ctx, "user", userInfo)
if err != nil {
// handle error
}Each key can only be set once. Repeated attempts return an ErrKeyAlreadySet error.
Use the Get function to retrieve a value:
value, err := ctxcache.Get[UserType](ctx, "user")
if err != nil {
// handle error
}Get is a generic function that requires specifying a type parameter to ensure type safety.
Calling the cancel function returned by Init clears all cached values:
cancel() // Clear cache and make it permanently unusableOnce cleared, subsequent Get or Set operations will return ErrCacheAlreadyCleared error.
The package defines the following error types:
ErrCacheNotInitialized: Cache is not initializedErrCacheAlreadyCleared: Cache has already been clearedErrKeyNotSet: Key is not setErrKeyAlreadySet: Key is already set
- HTTP Middleware: Initialize cache at request entry point and clean up at exit
- Authenticated User Info: Store authenticated user objects
- Permission Data: Pass user permission lists
- Trace Metadata: Carry trace context information
- Computed Intermediates: Share computed intermediate values across call chains
package main
import (
"context"
"fmt"
"github.com/go-spring/stdlib/ctxcache"
)
type User struct {
ID int
Name string
}
func main() {
ctx := context.Background()
// Initialize cache
ctx, cancel := ctxcache.Init(ctx)
defer cancel()
// Set user info
user := User{ID: 1, Name: "Alice"}
if err := ctxcache.Set(ctx, "user", user); err != nil {
panic(err)
}
// Get user info in downstream code
retrievedUser, err := ctxcache.Get[User](ctx, "user")
if err != nil {
panic(err)
}
fmt.Printf("User: %+v\n", retrievedUser)
}ctxcacheis not a general-purpose cache. It is designed for structured, short-lived, in-process context data- Each key can only be assigned once. This is intentional design to ensure data immutability
- The cancel function should be called at request boundaries to ensure request-scoped data is properly cleaned up
- Once cleared, the cache becomes permanently unusable and should not be used again