diff --git a/dsmiddleware/rediscache/example_test.go b/dsmiddleware/rediscache/example_test.go index 0735366..d1efedc 100644 --- a/dsmiddleware/rediscache/example_test.go +++ b/dsmiddleware/rediscache/example_test.go @@ -2,10 +2,9 @@ package rediscache_test import ( "context" - "net" - "time" + "github.com/go-redis/redis/v7" + "os" - "github.com/gomodule/redigo/redis" "go.mercari.io/datastore/clouddatastore" "go.mercari.io/datastore/dsmiddleware/rediscache" "go.mercari.io/datastore/internal/testutils" @@ -22,14 +21,11 @@ func Example_howToUse() { defer client.Close() defer testutils.CleanUpAllEntities(ctx, client) - dial, err := net.Dial("tcp", redisAddress) - if err != nil { - panic(err) - } - defer dial.Close() - conn := redis.NewConn(dial, 100*time.Millisecond, 100*time.Millisecond) - defer conn.Close() + redisClient := redis.NewClient(&redis.Options{ + Addr: os.Getenv("REDIS_HOST") + ":" + os.Getenv("REDIS_PORT"), + DB: 0, + }) - mw := rediscache.New(conn) + mw := rediscache.New(redisClient) client.AppendMiddleware(mw) } diff --git a/dsmiddleware/rediscache/rediscache.go b/dsmiddleware/rediscache/rediscache.go index 1c9d0fe..25a8ea6 100644 --- a/dsmiddleware/rediscache/rediscache.go +++ b/dsmiddleware/rediscache/rediscache.go @@ -5,11 +5,10 @@ import ( "context" "encoding/gob" "errors" - "time" - - "github.com/gomodule/redigo/redis" + "github.com/go-redis/redis/v7" "go.mercari.io/datastore" "go.mercari.io/datastore/dsmiddleware/storagecache" + "time" ) var _ storagecache.Storage = &cacheHandler{} @@ -18,7 +17,7 @@ var _ datastore.Middleware = &cacheHandler{} const defaultExpiration = 15 * time.Minute // New Redis cache middleware creates & returns. -func New(conn redis.Conn, opts ...CacheOption) interface { +func New(conn *redis.Client, opts ...CacheOption) interface { datastore.Middleware storagecache.Storage } { @@ -53,7 +52,7 @@ type cacheHandler struct { datastore.Middleware stOpts *storagecache.Options - conn redis.Conn + conn *redis.Client expireDuration time.Duration logf func(ctx context.Context, format string, args ...interface{}) cacheKey func(key datastore.Key) string @@ -68,12 +67,7 @@ func (ch *cacheHandler) SetMulti(ctx context.Context, cis []*storagecache.CacheI ch.logf(ctx, "dsmiddleware/rediscache.SetMulti: incoming len=%d", len(cis)) - err := ch.conn.Send("MULTI") - if err != nil { - ch.logf(ctx, `dsmiddleware/rediscache.SetMulti: conn.Send("MULTI") err=%s`, err.Error()) - return err - } - + pipe := ch.conn.TxPipeline() cnt := 0 for _, ci := range cis { if ci.Key.Incomplete() { @@ -90,13 +84,13 @@ func (ch *cacheHandler) SetMulti(ctx context.Context, cis []*storagecache.CacheI cacheValue := buf.Bytes() if ch.expireDuration <= 0 { - err = ch.conn.Send("SET", cacheKey, cacheValue) + err = pipe.Set(cacheKey, cacheValue, 0).Err() if err != nil { ch.logf(ctx, `dsmiddleware/rediscache.SetMulti: conn.Send("SET", "%s", ...) err=%s`, cacheKey, err.Error()) return err } } else { - err = ch.conn.Send("SET", cacheKey, cacheValue, "PX", int64(ch.expireDuration/time.Millisecond)) + err = ch.conn.Set(cacheKey, cacheValue, ch.expireDuration).Err() if err != nil { ch.logf(ctx, `dsmiddleware/rediscache.SetMulti: conn.Send("SET", "%s", ..., "PX", %d) err=%s`, cacheKey, ch.expireDuration/time.Millisecond, err.Error()) return err @@ -106,8 +100,7 @@ func (ch *cacheHandler) SetMulti(ctx context.Context, cis []*storagecache.CacheI } ch.logf(ctx, "dsmiddleware/rediscache.SetMulti: len=%d", cnt) - - _, err = ch.conn.Do("EXEC") + _, err := pipe.Exec() if err != nil { ch.logf(ctx, `dsmiddleware/rediscache.SetMulti: conn.Send("EXEC") err=%s`, err.Error()) return err @@ -120,40 +113,38 @@ func (ch *cacheHandler) GetMulti(ctx context.Context, keys []datastore.Key) ([]* ch.logf(ctx, "dsmiddleware/rediscache.GetMulti: incoming len=%d", len(keys)) - err := ch.conn.Send("MULTI") - if err != nil { - ch.logf(ctx, `dsmiddleware/rediscache.GetMulti: conn.Send("MULTI") err=%s`, err.Error()) - return nil, err - } + pipe := ch.conn.TxPipeline() resultList := make([]*storagecache.CacheItem, len(keys)) + resps := make([]*redis.StringCmd, len(keys)) for idx, key := range keys { cacheKey := ch.cacheKey(key) resultList[idx] = &storagecache.CacheItem{ Key: key, } - err := ch.conn.Send("GET", cacheKey) - if err != nil { - ch.logf(ctx, `dsmiddleware/rediscache.GetMulti: conn.Send("GET", "%s") err=%s`, cacheKey, err.Error()) - return nil, err - } + resps[idx] = pipe.Get(cacheKey) } - resp, err := ch.conn.Do("EXEC") - if err != nil { + _, err := pipe.Exec() + if err != nil && err != redis.Nil { ch.logf(ctx, `dsmiddleware/rediscache.GetMulti: conn.Do("EXEC") err=%s`, err.Error()) return nil, err } - bs, err := redis.ByteSlices(resp, nil) - if err != nil { - ch.logf(ctx, `dsmiddleware/rediscache.GetMulti: redis.ByteSlices err=%s`, err.Error()) - return nil, err - } hit := 0 miss := 0 - for idx, b := range bs { + for idx, r := range resps { + b, err := r.Bytes() + if err == redis.Nil { + resultList[idx] = nil + miss++ + continue + } + if err != nil { + ch.logf(ctx, `dsmiddleware/rediscache.GetMulti: conn.Send("GET") err=%s`, err.Error()) + return nil, err + } if len(b) == 0 { resultList[idx] = nil miss++ @@ -177,6 +168,7 @@ func (ch *cacheHandler) GetMulti(ctx context.Context, keys []datastore.Key) ([]* resultList[idx].PropertyList = ps hit++ + } ch.logf(ctx, "dsmiddleware/rediscache.GetMulti: hit=%d miss=%d", hit, miss) @@ -187,23 +179,19 @@ func (ch *cacheHandler) GetMulti(ctx context.Context, keys []datastore.Key) ([]* func (ch *cacheHandler) DeleteMulti(ctx context.Context, keys []datastore.Key) error { ch.logf(ctx, "dsmiddleware/rediscache.DeleteMulti: incoming len=%d", len(keys)) - err := ch.conn.Send("MULTI") - if err != nil { - ch.logf(ctx, `dsmiddleware/rediscache.DeleteMulti: conn.Send("MULTI") err=%s`, err.Error()) - return err - } + pipe := ch.conn.TxPipeline() for _, key := range keys { cacheKey := ch.cacheKey(key) - err = ch.conn.Send("DEL", cacheKey) + err := pipe.Del(cacheKey).Err() if err != nil { ch.logf(ctx, `dsmiddleware/rediscache.DeleteMulti: conn.Send("DEL", "%s") err=%s`, cacheKey, err.Error()) return err } } - _, err = ch.conn.Do("EXEC") + _, err := pipe.Exec() if err != nil { ch.logf(ctx, `dsmiddleware/rediscache.DeleteMulti: conn.Send("EXEC") err=%s`, err.Error()) return err diff --git a/dsmiddleware/rediscache/rediscache_test.go b/dsmiddleware/rediscache/rediscache_test.go index 5d01c4a..dc1942f 100644 --- a/dsmiddleware/rediscache/rediscache_test.go +++ b/dsmiddleware/rediscache/rediscache_test.go @@ -9,10 +9,9 @@ import ( "regexp" "strings" "testing" - "time" "github.com/MakeNowJust/heredoc" - "github.com/gomodule/redigo/redis" + redis "github.com/go-redis/redis/v7" "go.mercari.io/datastore" "go.mercari.io/datastore/dsmiddleware/dslog" "go.mercari.io/datastore/dsmiddleware/storagecache" @@ -57,15 +56,20 @@ func TestRedisCache_Basic(t *testing.T) { t.Fatal(err) } defer dial.Close() - conn := redis.NewConn(dial, 100*time.Millisecond, 100*time.Millisecond) - defer conn.Close() + + + redisClient := redis.NewClient(&redis.Options{ + Addr: os.Getenv("REDIS_HOST") + ":" + os.Getenv("REDIS_PORT"), + DB: 0, + }) + ch := New( - conn, + redisClient, WithLogger(logf), ) client.AppendMiddleware(ch) defer func() { - _, err := conn.Do("FLUSHALL") + _, err := redisClient.FlushAll().Result() if err != nil { t.Fatal(err) } @@ -169,16 +173,19 @@ func TestRedisCache_BasicWithoutExpire(t *testing.T) { t.Fatal(err) } defer dial.Close() - conn := redis.NewConn(dial, 100*time.Millisecond, 100*time.Millisecond) - defer conn.Close() + + redisClient := redis.NewClient(&redis.Options{ + Addr: os.Getenv("REDIS_HOST") + ":" + os.Getenv("REDIS_PORT"), + DB: 0, + }) + ch := New( - conn, - WithExpireDuration(0), + redisClient, WithLogger(logf), ) client.AppendMiddleware(ch) defer func() { - _, err := conn.Do("FLUSHALL") + _, err := redisClient.FlushAll().Result() if err != nil { t.Fatal(err) } @@ -282,15 +289,20 @@ func TestRedisCache_Query(t *testing.T) { t.Fatal(err) } defer dial.Close() - conn := redis.NewConn(dial, 100*time.Millisecond, 100*time.Millisecond) - defer conn.Close() + + + redisClient := redis.NewClient(&redis.Options{ + Addr: os.Getenv("REDIS_HOST") + ":" + os.Getenv("REDIS_PORT"), + DB: 0, + }) + ch := New( - conn, + redisClient, WithLogger(logf), ) client.AppendMiddleware(ch) defer func() { - _, err := conn.Do("FLUSHALL") + _, err := redisClient.FlushAll().Result() if err != nil { t.Fatal(err) } @@ -416,15 +428,20 @@ func TestRedisCache_Transaction(t *testing.T) { t.Fatal(err) } defer dial.Close() - conn := redis.NewConn(dial, 100*time.Millisecond, 100*time.Millisecond) - defer conn.Close() + + + redisClient := redis.NewClient(&redis.Options{ + Addr: os.Getenv("REDIS_HOST") + ":" + os.Getenv("REDIS_PORT"), + DB: 0, + }) + ch := New( - conn, + redisClient, WithLogger(logf), ) client.AppendMiddleware(ch) defer func() { - _, err := conn.Do("FLUSHALL") + _, err := redisClient.FlushAll().Result() if err != nil { t.Fatal(err) } @@ -628,15 +645,20 @@ func TestRedisCache_MultiError(t *testing.T) { t.Fatal(err) } defer dial.Close() - conn := redis.NewConn(dial, 100*time.Millisecond, 100*time.Millisecond) - defer conn.Close() + + + redisClient := redis.NewClient(&redis.Options{ + Addr: os.Getenv("REDIS_HOST") + ":" + os.Getenv("REDIS_PORT"), + DB: 0, + }) + ch := New( - conn, + redisClient, WithLogger(logf), ) client.AppendMiddleware(ch) defer func() { - _, err := conn.Do("FLUSHALL") + _, err := redisClient.FlushAll().Result() if err != nil { t.Fatal(err) } diff --git a/go.mod b/go.mod index 77fb66a..7d629a8 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/favclip/jwg v1.1.0 github.com/favclip/qbg v1.1.1 github.com/favclip/testerator v0.0.0-20181109065310-c967692c9c65 + github.com/go-redis/redis/v7 v7.0.0-beta.4 github.com/golang/protobuf v1.3.2 github.com/gomodule/redigo v2.0.0+incompatible github.com/pmezard/go-difflib v1.0.0 // indirect diff --git a/go.sum b/go.sum index 5412f67..a856573 100644 --- a/go.sum +++ b/go.sum @@ -25,6 +25,10 @@ github.com/favclip/qbg v1.1.1 h1:+XMzBTY7L2lvhrurHB+QYqzW0RZtRsNoSitpGnmbgYE= github.com/favclip/qbg v1.1.1/go.mod h1:MVeXoe5BQr3gFch7dOojqXoMdI+vOs81mGmfBy0vFPo= github.com/favclip/testerator v0.0.0-20181109065310-c967692c9c65 h1:Kru5zSUxK6YkIyh2Eg9dNHoq0c0UO767Yuz5n+3AOhw= github.com/favclip/testerator v0.0.0-20181109065310-c967692c9c65/go.mod h1:cVtAzsIzVl0mgwdBBhpGg08LJ49tLVxiIpmCut59GI4= +github.com/fsnotify/fsnotify v1.4.7 h1:IXs+QLmnXW2CcXuY+8Mzv/fWEsPGWxqefPtCP5CnV9I= +github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= +github.com/go-redis/redis/v7 v7.0.0-beta.4 h1:p6z7Pde69EGRWvlC++y8aFcaWegyrKHzOBGo0zUACTQ= +github.com/go-redis/redis/v7 v7.0.0-beta.4/go.mod h1:xhhSbUMTsleRPur+Vgx9sUHtyN33bdjxY+9/0n9Ig8s= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= @@ -52,12 +56,21 @@ github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5m github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1 h1:0hERBMJE1eitiLkihrMvRVBYAkpHzc/J3QdDN+dAcgU= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hpcloud/tail v1.0.0 h1:nfCOvKYfkgYP8hkirhJocXT2+zOD8yUNjXaWfTlyFKI= +github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024 h1:rBMNdlhTLzJjJSDIjNEXX1Pz3Hmwmz91v+zycvx9PJc= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/ginkgo v1.8.0 h1:VkHVNpR4iVnU8XQR6DBm8BqYjN7CRzw+xKUbVVbbW9w= +github.com/onsi/ginkgo v1.8.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= +github.com/onsi/gomega v1.5.0 h1:izbySO9zDPmjJ8rDjLvkA2zJHIo+HkYXHnf7eN7SSyo= +github.com/onsi/gomega v1.5.0/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1CpauHY= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= @@ -81,6 +94,7 @@ golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180906233101-161cd47e91fd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= @@ -102,6 +116,7 @@ golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJ golang.org/x/sync v0.0.0-20190423024810-112230192c58 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -154,8 +169,16 @@ google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiq google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0 h1:AzbTB6ux+okLTzP8Ru1Xs41C303zdcfEht7MQnYJt5A= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/fsnotify.v1 v1.4.7 h1:xOHLXZwVvI9hhs+cLKq5+I5onOuwQLhQwiu63xxlHs4= +gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7 h1:uRGJdciOHaEIrze2W8Q3AKkepLTh2hOroT7a+7czfdQ= +gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= +gopkg.in/yaml.v2 v2.2.1 h1:mUhvW9EsL+naU5Q3cakzfE91YhliOondGd6ZrsDBHQE= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4=