• v1.0.0 df7aa63e5c

    Rene Nochebuena released this 2026-05-29 09:59:33 -06:00 | 0 commits to main since this release

    v1.0.0

    code.nochebuena.dev/einherjar/cache-valkey


    Architecture Decisions Resolved

    Decision Outcome
    Flat package No sub-packages — all adapters wrap the same Provider; no sub-concern is independently usable without the connection (see ADR-001)
    Provider interface Six common ops + Native() vk.Client escape hatch — follows micro-lib minio pattern (see ADR-002)
    Adapter constructors Take Provider, not vk.Client — adapters testable with mockProvider, no live server required (see ADR-003)
    IncrWithTTL implementation Lua script — atomic INCR + conditional EXPIRE; race-free fixed-window counter (see ADR-004)
    Health priority LevelDegraded — Valkey outage degrades, does not halt the service (see ADR-005)

    API

    import cachevalkey "code.nochebuena.dev/einherjar/cache-valkey"
    
    // Interfaces
    type Provider interface {
        Get(ctx context.Context, key string) (string, bool, error)
        Set(ctx context.Context, key string, value string, ttl time.Duration) error
        Del(ctx context.Context, keys ...string) error
        Exists(ctx context.Context, key string) (bool, error)
        Expire(ctx context.Context, key string, ttl time.Duration) error
        IncrWithTTL(ctx context.Context, key string, ttl time.Duration) (int64, error)
        Native() vk.Client
    }
    type Component interface {
        lifecycle.Component
        observability.Checkable
        observability.Identifiable
        Provider
    }
    
    // Config (caarlos0/env compatible)
    type Config struct {
        Addrs             []string // EINHERJAR_VALKEY_ADDRS,required
        Password          string   // EINHERJAR_VALKEY_PASSWORD
        SelectDB          int      // EINHERJAR_VALKEY_DB          (default: 0)
        CacheSizeEachConn int      // EINHERJAR_VALKEY_CLIENT_CACHE_MB (default: 0)
    }
    
    // Constructor
    func New(logger logging.Logger, cfg Config) Component
    
    // Adapters (duck-typed — no cross-module import required)
    func NewPermissionCache(p Provider) *PermissionCache     // → auth/rbac.Cache
    func NewRateLimiterStore(p Provider, window time.Duration, limit int64) *RateLimiterStore // → web/mw.RateLimiterStore
    func NewBlacklist(p Provider) *Blacklist                 // → auth-jwt.Blacklist
    

    Wiring example

    vk := cachevalkey.New(logger, cfg)
    launcher.Register(vk)
    health.Register(vk)
    
    // Create adapters — each satisfies one interface in another module.
    // Go's structural typing handles the assignment; no cast required.
    permCache   := cachevalkey.NewPermissionCache(vk)
    rateLimiter := cachevalkey.NewRateLimiterStore(vk, time.Second, 100)
    blacklist   := cachevalkey.NewBlacklist(vk)
    
    // Wire into consuming modules directly:
    permProvider := rbac.NewCachedPermissionProvider(permCache, baseProvider, rbac.CacheConfig{TTL: 5 * time.Minute})
    router.Use(mw.IPRateLimit(rateLimiter))
    pair, err := authjwt.RefreshTokenPair(ctx, signer, oldRefreshToken, blacklist, tokenCfg, newClaims)
    

    Install

    go get code.nochebuena.dev/einherjar/cache-valkey@v1.0.0
    

    Dependencies

    Module Version Role
    code.nochebuena.dev/einherjar/contracts v1.0.0 lifecycle.Component, observability.Checkable, logging.Logger
    code.nochebuena.dev/einherjar/core v1.0.0 xerrors
    github.com/valkey-io/valkey-go v1.0.54 Native Valkey client
    Downloads