mirror of
https://github.com/sablierapp/sablier.git
synced 2025-12-21 13:23:03 +01:00
There is a first implementation with ValKey that will allow to use redis APIs as a backend for Sablier with Hight Availability
82 lines
1.9 KiB
Go
82 lines
1.9 KiB
Go
package valkey
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"github.com/sablierapp/sablier/app/instance"
|
|
"github.com/sablierapp/sablier/pkg/store"
|
|
"github.com/valkey-io/valkey-go"
|
|
"log/slog"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
var _ store.Store = (*ValKey)(nil)
|
|
|
|
type ValKey struct {
|
|
Client valkey.Client
|
|
}
|
|
|
|
func New(ctx context.Context, client valkey.Client) (store.Store, error) {
|
|
err := client.Do(ctx, client.B().Ping().Build()).Error()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
err = client.Do(ctx, client.B().ConfigSet().ParameterValue().
|
|
ParameterValue("notify-keyspace-events", "KEx").
|
|
Build()).Error()
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
return &ValKey{Client: client}, nil
|
|
}
|
|
|
|
func (v *ValKey) Get(ctx context.Context, s string) (instance.State, error) {
|
|
b, err := v.Client.Do(ctx, v.Client.B().Get().Key(s).Build()).AsBytes()
|
|
if valkey.IsValkeyNil(err) {
|
|
return instance.State{}, store.ErrKeyNotFound
|
|
}
|
|
if err != nil {
|
|
return instance.State{}, err
|
|
}
|
|
|
|
var i instance.State
|
|
err = json.Unmarshal(b, &i)
|
|
if err != nil {
|
|
return instance.State{}, err
|
|
}
|
|
|
|
return i, nil
|
|
}
|
|
|
|
func (v *ValKey) Put(ctx context.Context, state instance.State, duration time.Duration) error {
|
|
value, err := json.Marshal(state)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return v.Client.Do(ctx, v.Client.B().Set().Key(state.Name).Value(string(value)).Ex(duration).Build()).Error()
|
|
}
|
|
|
|
func (v *ValKey) Delete(ctx context.Context, s string) error {
|
|
return v.Client.Do(ctx, v.Client.B().Del().Key(s).Build()).Error()
|
|
}
|
|
|
|
func (v *ValKey) OnExpire(ctx context.Context, f func(string)) error {
|
|
go func() {
|
|
err := v.Client.Receive(ctx, v.Client.B().Psubscribe().Pattern("__key*__:*").Build(), func(msg valkey.PubSubMessage) {
|
|
if msg.Message == "expired" {
|
|
split := strings.Split(msg.Channel, ":")
|
|
key := split[len(split)-1]
|
|
f(key)
|
|
}
|
|
})
|
|
if err != nil {
|
|
slog.Error("error subscribing", slog.Any("error", err))
|
|
}
|
|
}()
|
|
return nil
|
|
}
|