mirror of
https://github.com/pomerium/pomerium.git
synced 2025-05-01 03:16:31 +02:00
redis: use pubsub instead of keyspace events (#1450)
This commit is contained in:
parent
852c96f22f
commit
f4c61a0cdc
3 changed files with 21 additions and 39 deletions
|
@ -465,7 +465,6 @@ func (srv *Server) newDB(recordType string) (db storage.Backend, err error) {
|
||||||
db, err = redis.New(
|
db, err = redis.New(
|
||||||
srv.cfg.storageConnectionString,
|
srv.cfg.storageConnectionString,
|
||||||
recordType,
|
recordType,
|
||||||
int64(srv.cfg.deletePermanentlyAfter.Seconds()),
|
|
||||||
redis.WithTLSConfig(tlsConfig),
|
redis.WithTLSConfig(tlsConfig),
|
||||||
)
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
|
@ -26,34 +26,33 @@ import (
|
||||||
|
|
||||||
// Name is the storage type name for redis backend.
|
// Name is the storage type name for redis backend.
|
||||||
const Name = config.StorageRedisName
|
const Name = config.StorageRedisName
|
||||||
const watchAction = "zadd"
|
|
||||||
|
|
||||||
var _ storage.Backend = (*DB)(nil)
|
var _ storage.Backend = (*DB)(nil)
|
||||||
|
|
||||||
// DB wraps redis conn to interact with redis server.
|
// DB wraps redis conn to interact with redis server.
|
||||||
type DB struct {
|
type DB struct {
|
||||||
pool *redis.Pool
|
pool *redis.Pool
|
||||||
deletePermanentlyAfter int64
|
recordType string
|
||||||
recordType string
|
lastVersionKey string
|
||||||
lastVersionKey string
|
lastVersionChannelKey string
|
||||||
versionSet string
|
versionSet string
|
||||||
deletedSet string
|
deletedSet string
|
||||||
tlsConfig *tls.Config
|
tlsConfig *tls.Config
|
||||||
notifyChMu sync.Mutex
|
notifyChMu sync.Mutex
|
||||||
|
|
||||||
closeOnce sync.Once
|
closeOnce sync.Once
|
||||||
closed chan struct{}
|
closed chan struct{}
|
||||||
}
|
}
|
||||||
|
|
||||||
// New returns new DB instance.
|
// New returns new DB instance.
|
||||||
func New(rawURL, recordType string, deletePermanentAfter int64, opts ...Option) (*DB, error) {
|
func New(rawURL, recordType string, opts ...Option) (*DB, error) {
|
||||||
db := &DB{
|
db := &DB{
|
||||||
deletePermanentlyAfter: deletePermanentAfter,
|
recordType: recordType,
|
||||||
recordType: recordType,
|
versionSet: recordType + "_version_set",
|
||||||
versionSet: recordType + "_version_set",
|
deletedSet: recordType + "_deleted_set",
|
||||||
deletedSet: recordType + "_deleted_set",
|
lastVersionKey: recordType + "_last_version",
|
||||||
lastVersionKey: recordType + "_last_version",
|
lastVersionChannelKey: recordType + "_last_version_ch",
|
||||||
closed: make(chan struct{}),
|
closed: make(chan struct{}),
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, o := range opts {
|
for _, o := range opts {
|
||||||
|
@ -122,6 +121,7 @@ func (db *DB) Put(ctx context.Context, id string, data *anypb.Any) (err error) {
|
||||||
{"MULTI": nil},
|
{"MULTI": nil},
|
||||||
{"HSET": {db.recordType, id, string(b)}},
|
{"HSET": {db.recordType, id, string(b)}},
|
||||||
{"ZADD": {db.versionSet, lastVersion, id}},
|
{"ZADD": {db.versionSet, lastVersion, id}},
|
||||||
|
{"PUBLISH": {db.lastVersionChannelKey, lastVersion}},
|
||||||
}
|
}
|
||||||
if err := db.tx(c, cmds); err != nil {
|
if err := db.tx(c, cmds); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -217,6 +217,7 @@ func (db *DB) Delete(ctx context.Context, id string) (err error) {
|
||||||
{"HSET": {db.recordType, id, string(b)}},
|
{"HSET": {db.recordType, id, string(b)}},
|
||||||
{"SADD": {db.deletedSet, id}},
|
{"SADD": {db.deletedSet, id}},
|
||||||
{"ZADD": {db.versionSet, lastVersion, id}},
|
{"ZADD": {db.versionSet, lastVersion, id}},
|
||||||
|
{"PUBLISH": {db.lastVersionChannelKey, lastVersion}},
|
||||||
}
|
}
|
||||||
if err := db.tx(c, cmds); err != nil {
|
if err := db.tx(c, cmds); err != nil {
|
||||||
return err
|
return err
|
||||||
|
@ -265,7 +266,7 @@ func (db *DB) doNotifyLoop(ctx context.Context, ch chan struct{}) {
|
||||||
psc.Conn.Close()
|
psc.Conn.Close()
|
||||||
}(&psc)
|
}(&psc)
|
||||||
|
|
||||||
if err := db.subscribeRedisChannel(&psc); err != nil {
|
if err := psc.Subscribe(db.lastVersionChannelKey); err != nil {
|
||||||
log.Error().Err(err).Msg("failed to subscribe to version set channel")
|
log.Error().Err(err).Msg("failed to subscribe to version set channel")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
@ -281,9 +282,6 @@ func (db *DB) doNotifyLoop(ctx context.Context, ch chan struct{}) {
|
||||||
case redis.Message:
|
case redis.Message:
|
||||||
log.Debug().Str("action", string(v.Data)).Msg("got redis message")
|
log.Debug().Str("action", string(v.Data)).Msg("got redis message")
|
||||||
recordOperation(ctx, time.Now(), "sub_received", nil)
|
recordOperation(ctx, time.Now(), "sub_received", nil)
|
||||||
if string(v.Data) != watchAction {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
|
|
||||||
select {
|
select {
|
||||||
case <-db.closed:
|
case <-db.closed:
|
||||||
|
@ -315,7 +313,7 @@ func (db *DB) doNotifyLoop(ctx context.Context, ch chan struct{}) {
|
||||||
log.Warn().Msg("retry with new connection")
|
log.Warn().Msg("retry with new connection")
|
||||||
_ = psc.Conn.Close()
|
_ = psc.Conn.Close()
|
||||||
psc.Conn = db.pool.Get()
|
psc.Conn = db.pool.Get()
|
||||||
_ = db.subscribeRedisChannel(&psc)
|
_ = psc.Subscribe(db.lastVersionChannelKey)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -339,26 +337,11 @@ func (db *DB) watch(ctx context.Context, ch chan struct{}) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (db *DB) subscribeRedisChannel(psc *redis.PubSubConn) error {
|
|
||||||
return psc.PSubscribe("__keyspace*__:" + db.versionSet)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Watch returns a channel to the caller, when there is a change to the version set,
|
// Watch returns a channel to the caller, when there is a change to the version set,
|
||||||
// sending message to the channel to notify the caller.
|
// sending message to the channel to notify the caller.
|
||||||
func (db *DB) Watch(ctx context.Context) <-chan struct{} {
|
func (db *DB) Watch(ctx context.Context) <-chan struct{} {
|
||||||
ch := make(chan struct{})
|
ch := make(chan struct{})
|
||||||
go func() {
|
go db.watch(ctx, ch)
|
||||||
c := db.pool.Get()
|
|
||||||
// Setup notifications, we only care about changes to db.version_set.
|
|
||||||
if _, err := c.Do("CONFIG", "SET", "notify-keyspace-events", "Kz"); err != nil {
|
|
||||||
log.Error().Err(err).Msg("failed to setup redis notification")
|
|
||||||
c.Close()
|
|
||||||
return
|
|
||||||
}
|
|
||||||
c.Close()
|
|
||||||
db.watch(ctx, ch)
|
|
||||||
}()
|
|
||||||
|
|
||||||
return ch
|
return ch
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -73,7 +73,7 @@ func runWithRedisDockerImage(t *testing.T, runOpts *dockertest.RunOptions, withT
|
||||||
address := fmt.Sprintf(scheme+"://localhost:%s/0", resource.GetPort("6379/tcp"))
|
address := fmt.Sprintf(scheme+"://localhost:%s/0", resource.GetPort("6379/tcp"))
|
||||||
if err := pool.Retry(func() error {
|
if err := pool.Retry(func() error {
|
||||||
var err error
|
var err error
|
||||||
db, err = New(address, "record_type", int64(time.Hour.Seconds()), WithTLSConfig(tlsConfig(address, t)))
|
db, err = New(address, "record_type", WithTLSConfig(tlsConfig(address, t)))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue