Relay

Redis Store

Redis store for high-throughput, low-latency deployments.

The Redis store uses Grove KV with the redisdriver for key-value storage. It stores entities as JSON blobs and uses Redis sorted sets and sets for indexing and querying.

Usage

Standalone

import (
    "github.com/xraph/grove/kv"
    _ "github.com/xraph/grove/kv/drivers/redisdriver"
    redisstore "github.com/xraph/relay/store/redis"
)

store, err := kv.Open("redis", "redis://localhost:6379/0")
if err != nil {
    log.Fatal(err)
}

s := redisstore.New(store)

r, err := relay.New(relay.WithStore(s))

With Forge extension

When using the Forge extension with Grove KV, the store is resolved from the DI container:

app.Use(extension.New(
    extension.WithGroveKV(""),  // uses the default grove kv.Store
))

Or via YAML config:

extensions:
  relay:
    grove_kv: ""

Data model

Entities are stored as JSON blobs under prefixed keys. Indexes use Redis sorted sets (scored by timestamp) and sets for efficient lookup.

Key prefixes

PrefixPurpose
relay:evtype:<id>Event type entity
relay:ep:<id>Endpoint entity
relay:evt:<id>Event entity
relay:del:<id>Delivery entity
relay:dlq:<id>DLQ entry entity

Index keys

Key patternTypePurpose
relay:z:evtype:allSorted setAll event types by creation time
relay:z:ep:tenant:<tid>Sorted setEndpoints per tenant
relay:z:evt:allSorted setAll events by creation time
relay:z:evt:tenant:<tid>Sorted setEvents per tenant
relay:z:del:pendingSorted setPending deliveries by next_attempt_at
relay:z:del:ep:<eid>Sorted setDeliveries per endpoint
relay:z:dlq:allSorted setAll DLQ entries by failure time
relay:s:evtype:activeSetActive (non-deprecated) event type IDs
relay:s:ep:tenant:<tid>:enabledSetEnabled endpoint IDs per tenant

Unique constraints

Key patternPurpose
relay:u:evtype:name:<name>Event type name uniqueness
relay:u:evt:idem:<key>Idempotency key uniqueness

Migrations

Migrate() is a no-op -- Redis does not require schema migrations. Keys and indexes are created on demand as entities are stored.

Internals

AspectDetail
DriverGrove KV with redisdriver (go-redis v9)
MigrationsNo-op
DequeueSorted set range + atomic key update
TransactionsRedis single-key atomicity
JSON fieldsAll entities stored as JSON blobs
PaginationClient-side offset/limit on sorted set results
Pingkv.Ping(ctx)
CloseCloses the KV store

When to use

  • High-throughput, low-latency delivery pipelines.
  • When Redis is already part of your infrastructure.
  • Ephemeral or cache-friendly workloads where Redis persistence (RDB/AOF) is acceptable.
  • Workloads that benefit from Redis clustering for horizontal scaling.

Limitations

  • No multi-key transactions -- operations are atomic per key only.
  • Pagination is applied client-side after fetching sorted set members.
  • Data durability depends on Redis persistence configuration (RDB, AOF, or none).

On this page