mirror of
https://github.com/hanzokv/go.git
synced 2026-09-24 00:31:51 +00:00
feat(error): Add typed error for NOSCRIPT replies from Redis (#3738)
This commit is contained in:
@@ -2,6 +2,8 @@ package redis_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/rand"
|
||||
"crypto/sha1"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
@@ -8648,6 +8650,21 @@ var _ = Describe("Commands", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(vals).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("propagates NOSCRIPT errors on EVALSHA of an unknown digest", func() {
|
||||
digest := make([]byte, 32)
|
||||
_, err := rand.Read(digest)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
_, err = client.EvalSha(
|
||||
ctx,
|
||||
fmt.Sprintf("%x", sha1.Sum(digest)),
|
||||
[]string{},
|
||||
nil,
|
||||
).Result()
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(MatchError(redis.ErrNoScript))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("EvalRO", func() {
|
||||
@@ -8682,6 +8699,21 @@ var _ = Describe("Commands", func() {
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
Expect(vals).To(BeEmpty())
|
||||
})
|
||||
|
||||
It("propagates NOSCRIPT errors on EVALSHA_RO of an unknown digest", func() {
|
||||
digest := make([]byte, 32)
|
||||
_, err := rand.Read(digest)
|
||||
Expect(err).NotTo(HaveOccurred())
|
||||
|
||||
_, err = client.EvalShaRO(
|
||||
ctx,
|
||||
fmt.Sprintf("%x", sha1.Sum(digest)),
|
||||
[]string{},
|
||||
nil,
|
||||
).Result()
|
||||
Expect(err).To(HaveOccurred())
|
||||
Expect(err).To(MatchError(redis.ErrNoScript))
|
||||
})
|
||||
})
|
||||
|
||||
Describe("Functions", func() {
|
||||
|
||||
@@ -28,6 +28,11 @@ var ErrPoolTimeout = pool.ErrPoolTimeout
|
||||
// is used on a ClusterClient with keys in different slots.
|
||||
var ErrCrossSlot = proto.RedisError("CROSSSLOT Keys in request don't hash to the same slot")
|
||||
|
||||
// ErrNoScript is returned when EVALSHA is requested for a script digest that
|
||||
// is not available in the script cache. Note that this error text is reproduced
|
||||
// literally from that used by Redis.
|
||||
var ErrNoScript = proto.RedisError("NOSCRIPT No matching script. Please use EVAL.")
|
||||
|
||||
// HasErrorPrefix checks if the err is a Redis error and the message contains a prefix.
|
||||
func HasErrorPrefix(err error, prefix string) bool {
|
||||
var rErr Error
|
||||
|
||||
@@ -4,6 +4,7 @@ import (
|
||||
"context"
|
||||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"errors"
|
||||
"io"
|
||||
)
|
||||
|
||||
@@ -67,7 +68,7 @@ func (s *Script) EvalShaRO(ctx context.Context, c Scripter, keys []string, args
|
||||
// it is retried using EVAL.
|
||||
func (s *Script) Run(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
|
||||
r := s.EvalSha(ctx, c, keys, args...)
|
||||
if HasErrorPrefix(r.Err(), "NOSCRIPT") {
|
||||
if errors.Is(r.Err(), ErrNoScript) {
|
||||
return s.Eval(ctx, c, keys, args...)
|
||||
}
|
||||
return r
|
||||
@@ -77,7 +78,7 @@ func (s *Script) Run(ctx context.Context, c Scripter, keys []string, args ...int
|
||||
// it is retried using EVAL_RO.
|
||||
func (s *Script) RunRO(ctx context.Context, c Scripter, keys []string, args ...interface{}) *Cmd {
|
||||
r := s.EvalShaRO(ctx, c, keys, args...)
|
||||
if HasErrorPrefix(r.Err(), "NOSCRIPT") {
|
||||
if errors.Is(r.Err(), ErrNoScript) {
|
||||
return s.EvalRO(ctx, c, keys, args...)
|
||||
}
|
||||
return r
|
||||
|
||||
@@ -60,6 +60,11 @@ func (c cmdable) eval(ctx context.Context, name, payload string, keys []string,
|
||||
cmd.SetFirstKeyPos(3)
|
||||
}
|
||||
_ = c(ctx, cmd)
|
||||
if err := cmd.Err(); err != nil {
|
||||
if HasErrorPrefix(err, "NOSCRIPT") {
|
||||
cmd.SetErr(ErrNoScript)
|
||||
}
|
||||
}
|
||||
return cmd
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user