Loading...
Loading...
Generate Go cache implementations following GO modular architechture conventions. Use when creating cache layers in internal/modules/<module>/cache/ - user state caching, session caching, rate limiting data, temporary data storage, or any domain cache that uses Redis for fast data access with TTL support.
npx skill4agent add cristiano-pacheco/ai-tools go-cacheinternal/modules/<module>/ports/<cache_name>_cache.gointernal/modules/<module>/cache/<cache_name>_cache.goXxxCacheXxxCacheNewXxxCacheSetGetDeletebuildKeyinternal/modules/<module>/ports/<cache_name>_cache.gopackage ports
type UserActivatedCache interface {
Set(userID uint64) error
Get(userID uint64) (bool, error)
Delete(userID uint64) error
}internal/modules/<module>/cache/<cache_name>_cache.gopackage cache
import (
"context"
"errors"
"fmt"
"time"
"github.com/cristiano-pacheco/bricks/pkg/redis"
"github.com/cristiano-pacheco/pingo/internal/modules/<module>/ports"
)
const (
cacheKeyPrefix = "entity_name:"
cacheTTLMin = 23 * time.Hour
cacheTTLMax = 25 * time.Hour
)
type EntityCache struct {
redisClient redis.UniversalClient
}
var _ ports.EntityCache = (*EntityCache)(nil)
func NewEntityCache(redisClient redis.UniversalClient) *EntityCache {
return &EntityCache{
redisClient: redisClient,
}
}
func (c *EntityCache) Set(id uint64) error {
key := c.buildKey(id)
ctx := context.Background()
ttl := c.calculateTTL()
return c.redisClient.Set(ctx, key, "1", ttl).Err()
}
func (c *EntityCache) calculateTTL() time.Duration {
min := cacheTTLMin.Milliseconds()
max := cacheTTLMax.Milliseconds()
randomMs := min + rand.Int63n(max-min+1)
return time.Duration(randomMs) * time.Millisecond
}
func (c *EntityCache) Get(id uint64) (bool, error) {
key := c.buildKey(id)
ctx := context.Background()
result := c.redisClient.Get(ctx, key)
if err := result.Err(); err != nil {
if errors.Is(err, redisClient.Nil) {
return false, nil // Key does not exist
}
return false, err
}
return true, nil
}
func (c *EntityCache) Delete(id uint64) error {
key := c.buildKey(id)
ctx := context.Background()
return c.redisClient.Del(ctx, key).Err()
}
func (c *EntityCache) buildKey(id uint64) string {
return fmt.Sprintf("%s%d", cacheKeyPrefix, id)
}ports/user_activated_cache.gotype UserActivatedCache interface {
Set(userID uint64) error
Get(userID uint64) (bool, error)
Delete(userID uint64) error
}"1"false, nilerrors.Is(err, redisClient.Nil)ports/session_cache.gotype SessionCache interface {
Set(sessionID string, data SessionData) error
Get(sessionID string) (*SessionData, error)
Delete(sessionID string) error
}json.Marshaljson.Unmarshalnil, nilredis.UniversalClientgithub.com/cristiano-pacheco/bricks/pkg/redisSet(ctx, key, value, ttl)Get(ctx, key)Del(ctx, key)Exists(ctx, key)Incr(ctx, key)Expire(ctx, key, ttl)func (c *EntityCache) buildKey(id uint64) string {
return fmt.Sprintf("%s%d", cacheKeyPrefix, id)
}func (c *EntityCache) buildKey(id string) string {
return fmt.Sprintf("%s%s", cacheKeyPrefix, id)
}func (c *EntityCache) buildKey(userID uint64, resourceID string) string {
return fmt.Sprintf("%s%d:%s", cacheKeyPrefix, userID, resourceID)
}const (
cacheKeyPrefix = "entity_name:"
cacheTTLMin = 12 * time.Hour // Minimum TTL
cacheTTLMax = 24 * time.Hour // Maximum TTL
)import (
"math/rand"
"time"
)
func (c *EntityCache) calculateTTL() time.Duration {
min := cacheTTLMin.Milliseconds()
max := cacheTTLMax.Milliseconds()
randomMs := min + rand.Int63n(max-min+1)
return time.Duration(randomMs) * time.Millisecond
}4-6 minutes50-70 minutes12-25 hours6.5-7.5 daysresult := client.Get(ctx, key)
if err := result.Err(); err != nil {
if errors.Is(err, redisClient.Nil) {
return false, nil // Key doesn't exist - not an error
}
return false, err // Actual error
}context.Background()ctx := context.Background()func (c *EntityCache) Set(ctx context.Context, id uint64) error {
key := c.buildKey(id)
// Use provided ctx
return c.redisClient.Set(ctx, key, "1", cacheTTL).Err()
}XxxCacheportsXxxCachecacheNewXxxCachecacheKeyPrefixcacheTTLinternal/modules/<module>/module.gofx.Provide(
fx.Annotate(
cache.NewXxxCache,
fx.As(new(ports.XxxCache)),
),
),redis.UniversalClient"github.com/cristiano-pacheco/bricks/pkg/redis"ports/user_activated_cache.gopackage ports
type UserActivatedCache interface {
Set(userID uint64) error
Get(userID uint64) (bool, error)
Delete(userID uint64) error
}cache/user_activated_cache.gopackage cache
import (
"context"
"errors"
"fmt"
"strconv"
"time"
"github.com/cristiano-pacheco/bricks/pkg/redis"
"github.com/cristiano-pacheco/pingo/internal/modules/identity/ports"
)
const (
cacheKeyPrefix = "user_activated:"
cacheTTLMin = 23 * time.Hour
cacheTTLMax = 25 * time.Hour
)
type UserActivatedCache struct {
redisClient redis.UniversalClient
}
var _ ports.UserActivatedCache = (*UserActivatedCache)(nil)
func NewUserActivatedCache(redisClient redis.UniversalClient) *UserActivatedCache {
return &UserActivatedCache{
redisClient: redisClient,
}
}
func (c *UserActivatedCache) Set(userID uint64) error {
key := c.buildKey(userID)
ctx := context.Background()
ttl := c.calculateTTL()
return c.redisClient.Set(ctx, key, "1", ttl).Err()
}
func (c *UserActivatedCache) calculateTTL() time.Duration {
min := cacheTTLMin.Milliseconds()
max := cacheTTLMax.Milliseconds()
randomMs := min + rand.Int63n(max-min+1)
return time.Duration(randomMs) * time.Millisecond
}
func (c *UserActivatedCache) Get(userID uint64) (bool, error) {
key := c.buildKey(userID)
ctx := context.Background()
result := c.redisClient.Get(ctx, key)
if err := result.Err(); err != nil {
if errors.Is(err, redisClient.Nil) {
return false, nil
}
return false, err
}
return true, nil
}
func (c *UserActivatedCache) Delete(userID uint64) error {
key := c.buildKey(userID)
ctx := context.Background()
return c.redisClient.Del(ctx, key).Err()
}
func (c *UserActivatedCache) buildKey(userID uint64) string {
return fmt.Sprintf("%s%s", cacheKeyPrefix, strconv.FormatUint(userID, 10))
}module.gofx.Provide(
fx.Annotate(
cache.NewUserActivatedCache,
fx.As(new(ports.UserActivatedCache)),
),
),dto/user_session_dto.gopackage dto
import "time"
type UserSessionData struct {
UserID uint64 `json:"user_id"`
Email string `json:"email"`
Name string `json:"name"`
Roles []string `json:"roles"`
LastActivity time.Time `json:"last_activity"`
IPAddress string `json:"ip_address"`
}ports/user_session_cache.gopackage ports
import (
"time"
"github.com/cristiano-pacheco/pingo/internal/modules/identity/dto"
)
type UserSessionCache interface {
Set(sessionID string, data dto.UserSessionData) error
Get(sessionID string) (*dto.UserSessionData, error)
Delete(sessionID string) error
Exists(sessionID string) (bool, error)
}cache/user_session_cache.gopackage cache
import (
"context"
"encoding/json"
"errors"
"fmt"
"time"
"github.com/cristiano-pacheco/bricks/pkg/redis"
"github.com/cristiano-pacheco/pingo/internal/modules/identity/dto"
"github.com/cristiano-pacheco/pingo/internal/modules/identity/ports"
)
const (
sessionCacheKeyPrefix = "user_session:"
sessionCacheTTLMin = 50 * time.Minute
sessionCacheTTLMax = 70 * time.Minute
)
type UserSessionCache struct {
redisClient redis.UniversalClient
}
var _ ports.UserSessionCache = (*UserSessionCache)(nil)
func NewUserSessionCache(redisClient redis.UniversalClient) *UserSessionCache {
return &UserSessionCache{
redisClient: redisClient,
}
}
func (c *UserSessionCache) Set(sessionID string, data dto.UserSessionData) error {
key := c.buildKey(sessionID)
ctx := context.Background()
jsonData, err := json.Marshal(data)
if err != nil {
return fmt.Errorf("failed to marshal session data: %w", err)
}
ttl := c.calculateTTL()
return c.redisClient.Set(ctx, key, jsonData, ttl).Err()
}
func (c *UserSessionCache) calculateTTL() time.Duration {
min := sessionCacheTTLMin.Milliseconds()
max := sessionCacheTTLMax.Milliseconds()
randomMs := min + rand.Int63n(max-min+1)
return time.Duration(randomMs) * time.Millisecond
}
func (c *UserSessionCache) Get(sessionID string) (*dto.UserSessionData, error) {
key := c.buildKey(sessionID)
ctx := context.Background()
result := c.redisClient.Get(ctx, key)
if err := result.Err(); err != nil {
if errors.Is(err, redisClient.Nil) {
return nil, nil
}
return nil, err
}
jsonData, err := result.Bytes()
if err != nil {
return nil, fmt.Errorf("failed to get bytes: %w", err)
}
var data dto.UserSessionData
if err := json.Unmarshal(jsonData, &data); err != nil {
return nil, fmt.Errorf("failed to unmarshal session data: %w", err)
}
return &data, nil
}
func (c *UserSessionCache) Delete(sessionID string) error {
key := c.buildKey(sessionID)
ctx := context.Background()
return c.redisClient.Del(ctx, key).Err()
}
func (c *UserSessionCache) Exists(sessionID string) (bool, error) {
key := c.buildKey(sessionID)
ctx := context.Background()
result := c.redisClient.Exists(ctx, key)
if err := result.Err(); err != nil {
return false, err
}
return result.Val() > 0, nil
}
func (c *UserSessionCache) buildKey(sessionID string) string {
return fmt.Sprintf("%s%s", sessionCacheKeyPrefix, sessionID)
}module.gofx.Provide(
fx.Annotate(
cache.NewUserSessionCache,
fx.As(new(ports.UserSessionCache)),
),
),proto/user_profile.protosyntax = "proto3";
package identity;
option go_package = "github.com/cristiano-pacheco/pingo/internal/modules/identity/proto";
message UserProfile {
uint64 user_id = 1;
string email = 2;
string name = 3;
repeated string roles = 4;
int64 last_login = 5;
string avatar_url = 6;
}ports/user_profile_cache.gopackage ports
import (
"time"
"github.com/cristiano-pacheco/pingo/internal/modules/identity/proto"
)
type UserProfileCache interface {
Set(userID uint64, profile *proto.UserProfile) error
Get(userID uint64) (*proto.UserProfile, error)
Delete(userID uint64) error
}cache/user_profile_cache.gopackage cache
import (
"context"
"errors"
"fmt"
"time"
"github.com/cristiano-pacheco/bricks/pkg/redis"
"github.com/cristiano-pacheco/pingo/internal/modules/identity/ports"
"github.com/cristiano-pacheco/pingo/internal/modules/identity/proto"
"google.golang.org/protobuf/proto"
)
const (
profileCacheKeyPrefix = "user_profile:"
profileCacheTTLMin = 12 * time.Hour
profileCacheTTLMax = 24 * time.Hour
)
type UserProfileCache struct {
redisClient redis.UniversalClient
}
var _ ports.UserProfileCache = (*UserProfileCache)(nil)
func NewUserProfileCache(redisClient redis.UniversalClient) *UserProfileCache {
return &UserProfileCache{
redisClient: redisClient,
}
}
func (c *UserProfileCache) Set(userID uint64, profile *proto.UserProfile) error {
key := c.buildKey(userID)
ctx := context.Background()
data, err := proto.Marshal(profile)
if err != nil {
return fmt.Errorf("failed to marshal profile: %w", err)
}
ttl := c.calculateTTL()
return c.redisClient.Set(ctx, key, data, ttl).Err()
}
func (c *UserProfileCache) calculateTTL() time.Duration {
min := profileCacheTTLMin.Milliseconds()
max := profileCacheTTLMax.Milliseconds()
randomMs := min + rand.Int63n(max-min+1)
return time.Duration(randomMs) * time.Millisecond
}
func (c *UserProfileCache) Get(userID uint64) (*proto.UserProfile, error) {
key := c.buildKey(userID)
ctx := context.Background()
result := c.redisClient.Get(ctx, key)
if err := result.Err(); err != nil {
if errors.Is(err, redisClient.Nil) {
return nil, nil
}
return nil, err
}
data, err := result.Bytes()
if err != nil {
return nil, fmt.Errorf("failed to get bytes: %w", err)
}
var profile proto.UserProfile
if err := proto.Unmarshal(data, &profile); err != nil {
return nil, fmt.Errorf("failed to unmarshal profile: %w", err)
}
return &profile, nil
}
func (c *UserProfileCache) Delete(userID uint64) error {
key := c.buildKey(userID)
ctx := context.Background()
return c.redisClient.Del(ctx, key).Err()
}
func (c *UserProfileCache) buildKey(userID uint64) string {
return fmt.Sprintf("%s%d", profileCacheKeyPrefix, userID)
}module.gofx.Provide(
fx.Annotate(
cache.NewUserProfileCache,
fx.As(new(ports.UserProfileCache)),
),
),ports/cache/ports/<name>_cache.govar _ ports.XxxCache = (*XxxCache)(nil)*XxxCachecacheKeyPrefixcacheTTLMincacheTTLMaxcalculateTTL()buildKey()errors.Is(err, redisClient.Nil)context.Background()context.Contextredis.UniversalClientports/<name>_cache.gocache/<name>_cache.gomodule.gomake lintmake nilaway