-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(provider): redisfailover (sentinel) implementation (#2)
* feat(redis): implement username option (#36) Allows defining of the username to accompany the password. * Upgrade dependencies * Upgrade fasthttp to v1.20.0 * Upgrade fasthttp to v1.21.0 and other dependencies * Add support to Go v1.16.X * feat(provider): add redis failover provider (sentinel) Co-authored-by: Sergio Andres Virviescas Santana <[email protected]>
- Loading branch information
1 parent
5ce5eab
commit 16d1a8d
Showing
9 changed files
with
273 additions
and
10 deletions.
There are no files selected for viewing
Empty file.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
# Redis Fail Over | ||
|
||
Redis Fail Over (Sentinel) provider implementation. | ||
|
||
Better encoder: | ||
|
||
- Encode: `session.MSGPEncode` | ||
- Decode: `session.MSGPDecode` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package redisfailover | ||
|
||
import ( | ||
"errors" | ||
"fmt" | ||
) | ||
|
||
var errConfigMasterNameEmpty = errors.New("Config MasterName must not be empty") | ||
|
||
func errRedisConnection(err error) error { | ||
return fmt.Errorf("Redis connection error: %v", err) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,137 @@ | ||
package redisfailover | ||
|
||
import ( | ||
"context" | ||
"time" | ||
|
||
"github.com/go-redis/redis/v8" | ||
"github.com/valyala/bytebufferpool" | ||
) | ||
|
||
var all = []byte("*") | ||
|
||
// New returns a new configured redis provider | ||
func New(cfg Config) (*Provider, error) { | ||
if cfg.MasterName == "" { | ||
return nil, errConfigMasterNameEmpty | ||
} | ||
|
||
db := redis.NewFailoverClient(&redis.FailoverOptions{ | ||
MasterName: cfg.MasterName, | ||
SentinelAddrs: cfg.SentinelAddrs, | ||
RouteByLatency: cfg.RouteByLatency, | ||
RouteRandomly: cfg.RouteRandomly, | ||
SlaveOnly: cfg.SlaveOnly, | ||
Username: cfg.Username, | ||
Password: cfg.Password, | ||
DB: cfg.DB, | ||
MaxRetries: cfg.MaxRetries, | ||
MinRetryBackoff: cfg.MinRetryBackoff, | ||
MaxRetryBackoff: cfg.MaxRetryBackoff, | ||
DialTimeout: cfg.DialTimeout, | ||
ReadTimeout: cfg.ReadTimeout, | ||
WriteTimeout: cfg.WriteTimeout, | ||
PoolSize: cfg.PoolSize, | ||
MinIdleConns: cfg.MinIdleConns, | ||
MaxConnAge: cfg.MaxConnAge, | ||
PoolTimeout: cfg.PoolTimeout, | ||
IdleTimeout: cfg.IdleTimeout, | ||
IdleCheckFrequency: cfg.IdleCheckFrequency, | ||
TLSConfig: cfg.TLSConfig, | ||
}) | ||
|
||
if err := db.Ping(context.Background()).Err(); err != nil { | ||
return nil, errRedisConnection(err) | ||
} | ||
|
||
p := &Provider{ | ||
config: cfg, | ||
db: db, | ||
} | ||
|
||
return p, nil | ||
} | ||
|
||
func (p *Provider) getRedisSessionKey(sessionID []byte) string { | ||
key := bytebufferpool.Get() | ||
key.SetString(p.config.KeyPrefix) | ||
key.WriteString(":") | ||
key.Write(sessionID) | ||
|
||
keyStr := key.String() | ||
|
||
bytebufferpool.Put(key) | ||
|
||
return keyStr | ||
} | ||
|
||
// Get returns the data of the given session id | ||
func (p *Provider) Get(id []byte) ([]byte, error) { | ||
key := p.getRedisSessionKey(id) | ||
|
||
reply, err := p.db.Get(context.Background(), key).Bytes() | ||
if err != nil && err != redis.Nil { | ||
return nil, err | ||
} | ||
|
||
return reply, nil | ||
|
||
} | ||
|
||
// Save saves the session data and expiration from the given session id | ||
func (p *Provider) Save(id, data []byte, expiration time.Duration) error { | ||
key := p.getRedisSessionKey(id) | ||
|
||
return p.db.Set(context.Background(), key, data, expiration).Err() | ||
} | ||
|
||
// Regenerate updates the session id and expiration with the new session id | ||
// of the the given current session id | ||
func (p *Provider) Regenerate(id, newID []byte, expiration time.Duration) error { | ||
key := p.getRedisSessionKey(id) | ||
newKey := p.getRedisSessionKey(newID) | ||
|
||
exists, err := p.db.Exists(context.Background(), key).Result() | ||
if err != nil { | ||
return err | ||
} | ||
|
||
if exists > 0 { // Exist | ||
if err = p.db.Rename(context.Background(), key, newKey).Err(); err != nil { | ||
return err | ||
} | ||
|
||
if err = p.db.Expire(context.Background(), newKey, expiration).Err(); err != nil { | ||
return err | ||
} | ||
} | ||
|
||
return nil | ||
} | ||
|
||
// Destroy destroys the session from the given id | ||
func (p *Provider) Destroy(id []byte) error { | ||
key := p.getRedisSessionKey(id) | ||
|
||
return p.db.Del(context.Background(), key).Err() | ||
} | ||
|
||
// Count returns the total of stored sessions | ||
func (p *Provider) Count() int { | ||
reply, err := p.db.Keys(context.Background(), p.getRedisSessionKey(all)).Result() | ||
if err != nil { | ||
return 0 | ||
} | ||
|
||
return len(reply) | ||
} | ||
|
||
// NeedGC indicates if the GC needs to be run | ||
func (p *Provider) NeedGC() bool { | ||
return false | ||
} | ||
|
||
// GC destroys the expired sessions | ||
func (p *Provider) GC() error { | ||
return nil | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
package redisfailover | ||
|
||
import ( | ||
"crypto/tls" | ||
"time" | ||
|
||
"github.com/go-redis/redis/v8" | ||
) | ||
|
||
// Config provider settings | ||
type Config struct { | ||
// Key prefix | ||
KeyPrefix string | ||
|
||
// The sentinel master name. | ||
MasterName string | ||
|
||
// The sentinel nodes seed list (host:port). | ||
SentinelAddrs []string | ||
|
||
// The password for the sentinel connection if required (different to username/password). | ||
SentinelPassword string | ||
|
||
// Routes read-only commands to the closest node. | ||
RouteByLatency bool | ||
|
||
// Routes read-only commands in random order. | ||
RouteRandomly bool | ||
|
||
// Route read-only commands to slave nodes. | ||
SlaveOnly bool | ||
|
||
// Optional username. | ||
Username string | ||
|
||
// Optional password. Must match the password specified in the | ||
// requirepass server configuration option. | ||
Password string | ||
|
||
// Database to be selected after connecting to the server. | ||
DB int | ||
|
||
// Maximum number of retries before giving up. | ||
// Default is to not retry failed commands. | ||
MaxRetries int | ||
|
||
// Minimum backoff between each retry. | ||
// Default is 8 milliseconds; -1 disables backoff. | ||
MinRetryBackoff time.Duration | ||
|
||
// Maximum backoff between each retry. | ||
// Default is 512 milliseconds; -1 disables backoff. | ||
MaxRetryBackoff time.Duration | ||
|
||
// Dial timeout for establishing new connections. | ||
// Default is 5 seconds. | ||
DialTimeout time.Duration | ||
|
||
// Timeout for socket reads. If reached, commands will fail | ||
// with a timeout instead of blocking. Use value -1 for no timeout and 0 for default. | ||
// Default is 3 seconds. | ||
ReadTimeout time.Duration | ||
|
||
// Timeout for socket writes. If reached, commands will fail | ||
// with a timeout instead of blocking. | ||
// Default is ReadTimeout. | ||
WriteTimeout time.Duration | ||
|
||
// Maximum number of socket connections. | ||
// Default is 10 connections per every CPU as reported by runtime.NumCPU. | ||
PoolSize int | ||
|
||
// Minimum number of idle connections which is useful when establishing | ||
// new connection is slow. | ||
MinIdleConns int | ||
|
||
// Connection age at which client retires (closes) the connection. | ||
// Default is to not close aged connections. | ||
MaxConnAge time.Duration | ||
|
||
// Amount of time client waits for connection if all connections | ||
// are busy before returning an error. | ||
// Default is ReadTimeout + 1 second. | ||
PoolTimeout time.Duration | ||
|
||
// Amount of time after which client closes idle connections. | ||
// Should be less than server's timeout. | ||
// Default is 5 minutes. -1 disables idle timeout check. | ||
IdleTimeout time.Duration | ||
|
||
// Frequency of idle checks made by idle connections reaper. | ||
// Default is 1 minute. -1 disables idle connections reaper, | ||
// but idle connections are still discarded by the client | ||
// if IdleTimeout is set. | ||
IdleCheckFrequency time.Duration | ||
|
||
// TLS Config to use. When set TLS will be negotiated. | ||
TLSConfig *tls.Config | ||
} | ||
|
||
// Provider backend manager | ||
type Provider struct { | ||
config Config | ||
db *redis.Client | ||
} |