Skip to content

Redis

Connect to Redis with rk-boot and rk-db/redis plugin.

Overview#

We will use rk-boot & rk-db/redis to connect to Redis cluster. rk-db/redis uses go-redis as driver by default.

In order to demonstrate full example,we will use rk-gin to start a back end service with APIs as bellow.

  • GET /v1/get, get value
  • POST /v1/set, set value

Install#

  • rk-boot: Base package.
  • rk-gin: To start gin-gonic/gin microservice.
  • rk-db/redis: Plugin to connect to Redis with go-redis Client
go get github.com/rookie-ninja/rk-boot/v2
go get github.com/rookie-ninja/rk-gin/v2
go get github.com/rookie-ninja/rk-db/redis

Quick start#

1. Create boot.yaml#

---
gin:
  - name: server
    enabled: true
    port: 8080
redis:
  - name: redis                      # Required
    enabled: true                    # Required
    addrs: ["localhost:6379"]        # Required, One addr is for single, multiple is for cluster

2. Create main.go#

// Copyright (c) 2021 rookie-ninja
//
// Use of this source code is governed by an Apache-style
// license that can be found in the LICENSE file.
package main

import (
    "context"
    "github.com/gin-gonic/gin"
    "github.com/go-redis/redis/v8"
    "github.com/rookie-ninja/rk-boot/v2"
    "github.com/rookie-ninja/rk-db/redis"
    "github.com/rookie-ninja/rk-gin/v2/boot"
    "net/http"
    "time"
)

var redisClient *redis.Client

func main() {
    boot := rkboot.NewBoot()

    boot.Bootstrap(context.TODO())

    // Auto migrate database and init global userDb variable
    redisEntry := rkredis.GetRedisEntry("redis")
    redisClient, _ = redisEntry.GetClient()

    // Register APIs
    ginEntry := rkgin.GetGinEntry("server")
    ginEntry.Router.GET("/v1/get", Get)
    ginEntry.Router.POST("/v1/set", Set)

    boot.WaitForShutdownSig(context.TODO())
}

type KV struct {
    Key   string `json:"key"`
    Value string `json:"value"`
}

func Set(ctx *gin.Context) {
    payload := &KV{}

    if err := ctx.BindJSON(payload); err != nil {
        ctx.JSON(http.StatusInternalServerError, err)
        return
    }

    cmd := redisClient.Set(ctx.Request.Context(), payload.Key, payload.Value, time.Minute)

    if cmd.Err() != nil {
        ctx.JSON(http.StatusInternalServerError, cmd.Err())
        return
    }

    ctx.Status(http.StatusOK)
}

func Get(ctx *gin.Context) {
    key := ctx.Query("key")

    cmd := redisClient.Get(ctx.Request.Context(), key)

    if cmd.Err() != nil {
        if cmd.Err() == redis.Nil {
            ctx.JSON(http.StatusNotFound, "Key not found!")
        } else {
            ctx.JSON(http.StatusInternalServerError, cmd.Err())
        }
        return
    }

    payload := &KV{
        Key:   key,
        Value: cmd.Val(),
    }

    ctx.JSON(http.StatusOK, payload)
}

3.Start Redis locally#

$ docker run -it --rm --name rk-redis -p 6379:6379 redis

4.Directory hierarchy#

$ tree
.
├── boot.yaml
├── go.mod
├── go.sum
└── main.go

5.Start main.go#

$ go run main.go

2022-06-17T19:34:27.176+0800    INFO    redis/boot.go:268       Bootstrap RedisEntry    {"eventId": "8a3bc26c-00b3-4792-9563-d2664cd1ea8e", "entryName": "redis", "entryType": "RedisEntry", "clientType": "Single"}
2022-06-17T19:34:27.176+0800    INFO    redis/boot.go:276       Ping redis at [localhost:6379]
2022-06-17T19:34:27.181+0800    INFO    redis/boot.go:282       Ping redis at [localhost:6379] success
2022-06-17T19:34:27.181+0800    INFO    boot/gin_entry.go:666   Bootstrap GinEntry      {"eventId": "8a3bc26c-00b3-4792-9563-d2664cd1ea8e", "entryName": "server", "entryType": "GinEntry"}
------------------------------------------------------------------------
endTime=2022-06-17T19:34:27.181813+08:00
startTime=2022-06-17T19:34:27.181779+08:00
elapsedNano=33309
timezone=CST
ids={"eventId":"8a3bc26c-00b3-4792-9563-d2664cd1ea8e"}
app={"appName":"rk","appVersion":"local","entryName":"server","entryType":"GinEntry"}
env={"arch":"amd64","domain":"*","hostname":"lark.local","localIP":"10.8.0.2","os":"darwin"}
payloads={"ginPort":8080}
counters={}
pairs={}
timing={}
remoteAddr=localhost
operation=Bootstrap
resCode=OK
eventStatus=Ended
EOE

6.Validate#

6.1 Set KV#

$ curl -X POST "localhost:8080/v1/set" -d '{"key":"my-key","value":"my-value"}'

6.2 Get KV#

$ curl -X GET "localhost:8080/v1/get?key=my-key"
{"key":"my-key","value":"my-value"}

Full YAML options#

Almost all the fields were followed fields defined at Option

redis:
  - name: redis                      # Required
    enabled: true                    # Required
    addrs: ["localhost:6379"]        # Required, One addr is for single, multiple is for cluster
    domain: "*"                      # Optional
#    description: ""                 # Optional
#
#    # For HA
#    mansterName: ""                 # Optional, required when connecting to Sentinel(HA)
#    sentinelPass: ""                # Optional, default: ""
#
#    # For cluster
#    maxRedirects: 3                 # Optional, default: 3
#    readOnly: false                 # Optional, default: false
#    routeByLatency: false           # Optional, default: false
#    routeRandomly: false            # Optional, default: false
#
#    # Common options
#    db: 0                           # Optional, default: 0
#    user: ""                        # Optional, default: ""
#    pass: ""                        # Optional, default: ""
#    maxRetries: 3                   # Optional, default: 3
#    minRetryBackoffMs: 8            # Optional, default: 8
#    maxRetryBackoffMs: 512          # Optional, default: 512
#    dialTimeoutMs: 5000             # Optional, default: 5000 (5 seconds)
#    readTimeoutMs: 3000             # Optional, default: 3000 (3 seconds)
#    writeTimeoutMs: 1               # Optional, default: 3000 (3 seconds)
#    poolFIFO: false                 # Optional, default: false
#    poolSize: 10                    # Optional, default: 10
#    minIdleConn: 0                  # Optional, default: 0
#    maxConnAgeMs: 0                 # Optional, default: no aged connection
#    poolTimeoutMs: 1300             # Optional, default: 1300 (1.3 seconds)
#    idleTimeoutMs: 1                # Optional, default: 5 minutes
#    idleCheckFrequencyMs: 1         # Optional, default: 1 minutes
#
#    # For logger
#    loggerEntry: ""                 # Optional, default: default logger with STDOUT