1 package redis_test
2
3 import (
4 "context"
5 "errors"
6 "fmt"
7 "sync"
8 "time"
9
10 "github.com/redis/go-redis/v9"
11 )
12
13 var (
14 ctx = context.Background()
15 rdb *redis.Client
16 )
17
18 func init() {
19 rdb = redis.NewClient(&redis.Options{
20 Addr: ":6379",
21 DialTimeout: 10 * time.Second,
22 ReadTimeout: 30 * time.Second,
23 WriteTimeout: 30 * time.Second,
24 PoolSize: 10,
25 PoolTimeout: 30 * time.Second,
26 })
27 }
28
29 func ExampleNewClient() {
30 rdb := redis.NewClient(&redis.Options{
31 Addr: "localhost:6379",
32 Password: "",
33 DB: 0,
34 })
35
36 pong, err := rdb.Ping(ctx).Result()
37 fmt.Println(pong, err)
38
39 }
40
41 func ExampleParseURL() {
42 opt, err := redis.ParseURL("redis://:qwerty@localhost:6379/1?dial_timeout=5s")
43 if err != nil {
44 panic(err)
45 }
46 fmt.Println("addr is", opt.Addr)
47 fmt.Println("db is", opt.DB)
48 fmt.Println("password is", opt.Password)
49 fmt.Println("dial timeout is", opt.DialTimeout)
50
51
52 _ = redis.NewClient(opt)
53
54
55
56
57
58 }
59
60 func ExampleNewFailoverClient() {
61
62
63 rdb := redis.NewFailoverClient(&redis.FailoverOptions{
64 MasterName: "master",
65 SentinelAddrs: []string{":26379"},
66 })
67 rdb.Ping(ctx)
68 }
69
70 func ExampleNewClusterClient() {
71
72
73 rdb := redis.NewClusterClient(&redis.ClusterOptions{
74 Addrs: []string{":7000", ":7001", ":7002", ":7003", ":7004", ":7005"},
75 })
76 rdb.Ping(ctx)
77 }
78
79
80
81 func ExampleNewClusterClient_manualSetup() {
82
83
84
85 clusterSlots := func(ctx context.Context) ([]redis.ClusterSlot, error) {
86 slots := []redis.ClusterSlot{
87
88 {
89 Start: 0,
90 End: 8191,
91 Nodes: []redis.ClusterNode{{
92 Addr: ":7000",
93 }, {
94 Addr: ":8000",
95 }},
96 },
97
98 {
99 Start: 8192,
100 End: 16383,
101 Nodes: []redis.ClusterNode{{
102 Addr: ":7001",
103 }, {
104 Addr: ":8001",
105 }},
106 },
107 }
108 return slots, nil
109 }
110
111 rdb := redis.NewClusterClient(&redis.ClusterOptions{
112 ClusterSlots: clusterSlots,
113 RouteRandomly: true,
114 })
115 rdb.Ping(ctx)
116
117
118
119 rdb.ReloadState(ctx)
120 }
121
122 func ExampleNewRing() {
123 rdb := redis.NewRing(&redis.RingOptions{
124 Addrs: map[string]string{
125 "shard1": ":7000",
126 "shard2": ":7001",
127 "shard3": ":7002",
128 },
129 })
130 rdb.Ping(ctx)
131 }
132
133 func ExampleClient() {
134 err := rdb.Set(ctx, "key", "value", 0).Err()
135 if err != nil {
136 panic(err)
137 }
138
139 val, err := rdb.Get(ctx, "key").Result()
140 if err != nil {
141 panic(err)
142 }
143 fmt.Println("key", val)
144
145 val2, err := rdb.Get(ctx, "missing_key").Result()
146 if err == redis.Nil {
147 fmt.Println("missing_key does not exist")
148 } else if err != nil {
149 panic(err)
150 } else {
151 fmt.Println("missing_key", val2)
152 }
153
154
155 }
156
157 func ExampleConn_name() {
158 conn := rdb.Conn()
159
160 err := conn.ClientSetName(ctx, "foobar").Err()
161 if err != nil {
162 panic(err)
163 }
164
165
166 for i := 0; i < 10; i++ {
167 go rdb.Ping(ctx)
168 }
169
170 s, err := conn.ClientGetName(ctx).Result()
171 if err != nil {
172 panic(err)
173 }
174 fmt.Println(s)
175
176 }
177
178 func ExampleConn_client_setInfo_libraryVersion() {
179 conn := rdb.Conn()
180
181 err := conn.ClientSetInfo(ctx, redis.WithLibraryVersion("1.2.3")).Err()
182 if err != nil {
183 panic(err)
184 }
185
186
187 for i := 0; i < 10; i++ {
188 go rdb.Ping(ctx)
189 }
190
191 s, err := conn.ClientInfo(ctx).Result()
192 if err != nil {
193 panic(err)
194 }
195
196 fmt.Println(s.LibVer)
197
198 }
199
200 func ExampleClient_Set() {
201
202
203 err := rdb.Set(ctx, "key", "value", 0).Err()
204 if err != nil {
205 panic(err)
206 }
207
208
209 err = rdb.Set(ctx, "key2", "value", time.Hour).Err()
210 if err != nil {
211 panic(err)
212 }
213 }
214
215 func ExampleClient_SetEx() {
216 err := rdb.SetEx(ctx, "key", "value", time.Hour).Err()
217 if err != nil {
218 panic(err)
219 }
220 }
221
222 func ExampleClient_HSet() {
223
224 type ExampleUser struct {
225 Name string `redis:"name"`
226 Age int `redis:"age"`
227 }
228
229 items := ExampleUser{"jane", 22}
230
231 err := rdb.HSet(ctx, "user:1", items).Err()
232 if err != nil {
233 panic(err)
234 }
235 }
236
237 func ExampleClient_Incr() {
238 result, err := rdb.Incr(ctx, "counter").Result()
239 if err != nil {
240 panic(err)
241 }
242
243 fmt.Println(result)
244
245 }
246
247 func ExampleClient_BLPop() {
248 if err := rdb.RPush(ctx, "queue", "message").Err(); err != nil {
249 panic(err)
250 }
251
252
253 result, err := rdb.BLPop(ctx, 1*time.Second, "queue").Result()
254 if err != nil {
255 panic(err)
256 }
257
258 fmt.Println(result[0], result[1])
259
260 }
261
262 func ExampleClient_Scan() {
263 rdb.FlushDB(ctx)
264 for i := 0; i < 33; i++ {
265 err := rdb.Set(ctx, fmt.Sprintf("key%d", i), "value", 0).Err()
266 if err != nil {
267 panic(err)
268 }
269 }
270
271 var cursor uint64
272 var n int
273 for {
274 var keys []string
275 var err error
276 keys, cursor, err = rdb.Scan(ctx, cursor, "key*", 10).Result()
277 if err != nil {
278 panic(err)
279 }
280 n += len(keys)
281 if cursor == 0 {
282 break
283 }
284 }
285
286 fmt.Printf("found %d keys\n", n)
287
288 }
289
290 func ExampleClient_ScanType() {
291 rdb.FlushDB(ctx)
292 for i := 0; i < 33; i++ {
293 err := rdb.Set(ctx, fmt.Sprintf("key%d", i), "value", 0).Err()
294 if err != nil {
295 panic(err)
296 }
297 }
298
299 var cursor uint64
300 var n int
301 for {
302 var keys []string
303 var err error
304 keys, cursor, err = rdb.ScanType(ctx, cursor, "key*", 10, "string").Result()
305 if err != nil {
306 panic(err)
307 }
308 n += len(keys)
309 if cursor == 0 {
310 break
311 }
312 }
313
314 fmt.Printf("found %d keys\n", n)
315
316 }
317
318
319 func ExampleClient_ScanType_hashType() {
320 rdb.FlushDB(ctx)
321 for i := 0; i < 33; i++ {
322 err := rdb.HSet(context.TODO(), fmt.Sprintf("key%d", i), "value", "foo").Err()
323 if err != nil {
324 panic(err)
325 }
326 }
327
328 var allKeys []string
329 var cursor uint64
330 var err error
331
332 for {
333 var keysFromScan []string
334 keysFromScan, cursor, err = rdb.ScanType(context.TODO(), cursor, "key*", 10, "hash").Result()
335 if err != nil {
336 panic(err)
337 }
338 allKeys = append(allKeys, keysFromScan...)
339 if cursor == 0 {
340 break
341 }
342 }
343 fmt.Printf("%d keys ready for use", len(allKeys))
344
345 }
346
347
348
349 func ExampleMapStringStringCmd_Scan() {
350 rdb.FlushDB(ctx)
351 err := rdb.HMSet(ctx, "map",
352 "name", "hello",
353 "count", 123,
354 "correct", true).Err()
355 if err != nil {
356 panic(err)
357 }
358
359
360 res := rdb.HGetAll(ctx, "map")
361 if res.Err() != nil {
362 panic(res.Err())
363 }
364
365 type data struct {
366 Name string `redis:"name"`
367 Count int `redis:"count"`
368 Correct bool `redis:"correct"`
369 }
370
371
372 var d data
373 if err := res.Scan(&d); err != nil {
374 panic(err)
375 }
376
377 fmt.Println(d)
378
379 }
380
381
382
383 func ExampleSliceCmd_Scan() {
384 rdb.FlushDB(ctx)
385 err := rdb.MSet(ctx,
386 "name", "hello",
387 "count", 123,
388 "correct", true).Err()
389 if err != nil {
390 panic(err)
391 }
392
393 res := rdb.MGet(ctx, "name", "count", "empty", "correct")
394 if res.Err() != nil {
395 panic(res.Err())
396 }
397
398 type data struct {
399 Name string `redis:"name"`
400 Count int `redis:"count"`
401 Correct bool `redis:"correct"`
402 }
403
404
405 var d data
406 if err := res.Scan(&d); err != nil {
407 panic(err)
408 }
409
410 fmt.Println(d)
411
412 }
413
414 func ExampleClient_Pipelined() {
415 var incr *redis.IntCmd
416 _, err := rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error {
417 incr = pipe.Incr(ctx, "pipelined_counter")
418 pipe.Expire(ctx, "pipelined_counter", time.Hour)
419 return nil
420 })
421 fmt.Println(incr.Val(), err)
422
423 }
424
425 func ExampleClient_Pipeline() {
426 pipe := rdb.Pipeline()
427
428 incr := pipe.Incr(ctx, "pipeline_counter")
429 pipe.Expire(ctx, "pipeline_counter", time.Hour)
430
431
432
433
434
435
436
437 _, err := pipe.Exec(ctx)
438 fmt.Println(incr.Val(), err)
439
440 }
441
442 func ExampleClient_TxPipelined() {
443 var incr *redis.IntCmd
444 _, err := rdb.TxPipelined(ctx, func(pipe redis.Pipeliner) error {
445 incr = pipe.Incr(ctx, "tx_pipelined_counter")
446 pipe.Expire(ctx, "tx_pipelined_counter", time.Hour)
447 return nil
448 })
449 fmt.Println(incr.Val(), err)
450
451 }
452
453 func ExampleClient_TxPipeline() {
454 pipe := rdb.TxPipeline()
455
456 incr := pipe.Incr(ctx, "tx_pipeline_counter")
457 pipe.Expire(ctx, "tx_pipeline_counter", time.Hour)
458
459
460
461
462
463
464
465
466
467 _, err := pipe.Exec(ctx)
468 fmt.Println(incr.Val(), err)
469
470 }
471
472 func ExampleClient_Watch() {
473 const maxRetries = 10000
474
475
476 increment := func(key string) error {
477
478 txf := func(tx *redis.Tx) error {
479
480 n, err := tx.Get(ctx, key).Int()
481 if err != nil && err != redis.Nil {
482 return err
483 }
484
485
486 n++
487
488
489 _, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error {
490 pipe.Set(ctx, key, n, 0)
491 return nil
492 })
493 return err
494 }
495
496 for i := 0; i < maxRetries; i++ {
497 err := rdb.Watch(ctx, txf, key)
498 if err == nil {
499
500 return nil
501 }
502 if err == redis.TxFailedErr {
503
504 continue
505 }
506
507 return err
508 }
509
510 return errors.New("increment reached maximum number of retries")
511 }
512
513 var wg sync.WaitGroup
514 for i := 0; i < 100; i++ {
515 wg.Add(1)
516 go func() {
517 defer wg.Done()
518
519 if err := increment("counter3"); err != nil {
520 fmt.Println("increment error:", err)
521 }
522 }()
523 }
524 wg.Wait()
525
526 n, err := rdb.Get(ctx, "counter3").Int()
527 fmt.Println("ended with", n, err)
528
529 }
530
531 func ExamplePubSub() {
532 pubsub := rdb.Subscribe(ctx, "mychannel1")
533
534
535 _, err := pubsub.Receive(ctx)
536 if err != nil {
537 panic(err)
538 }
539
540
541 ch := pubsub.Channel()
542
543
544 err = rdb.Publish(ctx, "mychannel1", "hello").Err()
545 if err != nil {
546 panic(err)
547 }
548
549 time.AfterFunc(time.Second, func() {
550
551 _ = pubsub.Close()
552 })
553
554
555 for msg := range ch {
556 fmt.Println(msg.Channel, msg.Payload)
557 }
558
559
560 }
561
562 func ExamplePubSub_Receive() {
563 pubsub := rdb.Subscribe(ctx, "mychannel2")
564 defer pubsub.Close()
565
566 for i := 0; i < 2; i++ {
567
568 msgi, err := pubsub.ReceiveTimeout(ctx, time.Second)
569 if err != nil {
570 break
571 }
572
573 switch msg := msgi.(type) {
574 case *redis.Subscription:
575 fmt.Println("subscribed to", msg.Channel)
576
577 _, err := rdb.Publish(ctx, "mychannel2", "hello").Result()
578 if err != nil {
579 panic(err)
580 }
581 case *redis.Message:
582 fmt.Println("received", msg.Payload, "from", msg.Channel)
583 default:
584 panic("unreached")
585 }
586 }
587
588
589
590 }
591
592 func ExampleScript() {
593 IncrByXX := redis.NewScript(`
594 if redis.call("GET", KEYS[1]) ~= false then
595 return redis.call("INCRBY", KEYS[1], ARGV[1])
596 end
597 return false
598 `)
599
600 n, err := IncrByXX.Run(ctx, rdb, []string{"xx_counter"}, 2).Result()
601 fmt.Println(n, err)
602
603 err = rdb.Set(ctx, "xx_counter", "40", 0).Err()
604 if err != nil {
605 panic(err)
606 }
607
608 n, err = IncrByXX.Run(ctx, rdb, []string{"xx_counter"}, 2).Result()
609 fmt.Println(n, err)
610
611
612
613 }
614
615 func Example_customCommand() {
616 Get := func(ctx context.Context, rdb *redis.Client, key string) *redis.StringCmd {
617 cmd := redis.NewStringCmd(ctx, "get", key)
618 rdb.Process(ctx, cmd)
619 return cmd
620 }
621
622 v, err := Get(ctx, rdb, "key_does_not_exist").Result()
623 fmt.Printf("%q %s", v, err)
624
625 }
626
627 func Example_customCommand2() {
628 v, err := rdb.Do(ctx, "get", "key_does_not_exist").Text()
629 fmt.Printf("%q %s", v, err)
630
631 }
632
633 func ExampleScanIterator() {
634 iter := rdb.Scan(ctx, 0, "", 0).Iterator()
635 for iter.Next(ctx) {
636 fmt.Println(iter.Val())
637 }
638 if err := iter.Err(); err != nil {
639 panic(err)
640 }
641 }
642
643 func ExampleScanCmd_Iterator() {
644 iter := rdb.Scan(ctx, 0, "", 0).Iterator()
645 for iter.Next(ctx) {
646 fmt.Println(iter.Val())
647 }
648 if err := iter.Err(); err != nil {
649 panic(err)
650 }
651 }
652
653 func ExampleNewUniversalClient_simple() {
654 rdb := redis.NewUniversalClient(&redis.UniversalOptions{
655 Addrs: []string{":6379"},
656 })
657 defer rdb.Close()
658
659 rdb.Ping(ctx)
660 }
661
662 func ExampleNewUniversalClient_failover() {
663 rdb := redis.NewUniversalClient(&redis.UniversalOptions{
664 MasterName: "master",
665 Addrs: []string{":26379"},
666 })
667 defer rdb.Close()
668
669 rdb.Ping(ctx)
670 }
671
672 func ExampleNewUniversalClient_cluster() {
673 rdb := redis.NewUniversalClient(&redis.UniversalOptions{
674 Addrs: []string{":7000", ":7001", ":7002", ":7003", ":7004", ":7005"},
675 })
676 defer rdb.Close()
677
678 rdb.Ping(ctx)
679 }
680
681 func ExampleClient_SlowLogGet() {
682 if RECluster {
683
684 fmt.Println(2)
685 return
686 }
687 const key = "slowlog-log-slower-than"
688
689 old := rdb.ConfigGet(ctx, key).Val()
690 rdb.ConfigSet(ctx, key, "0")
691 defer rdb.ConfigSet(ctx, key, old[key])
692
693 if err := rdb.Do(ctx, "slowlog", "reset").Err(); err != nil {
694 panic(err)
695 }
696
697 rdb.Set(ctx, "test", "true", 0)
698
699 result, err := rdb.SlowLogGet(ctx, -1).Result()
700 if err != nil {
701 panic(err)
702 }
703 fmt.Println(len(result))
704
705 }
706
View as plain text