github.com/wfusion/gofusion@v1.1.14/common/infra/asynq/asynqmon/redis_info_handlers.go (about) 1 package asynqmon 2 3 import ( 4 "context" 5 "net/http" 6 "strings" 7 8 "github.com/redis/go-redis/v9" 9 10 "github.com/wfusion/gofusion/common/infra/asynq" 11 "github.com/wfusion/gofusion/common/utils/serialize/json" 12 ) 13 14 // **************************************************************************** 15 // This file defines: 16 // - http.Handler(s) for redis info related endpoints 17 // **************************************************************************** 18 19 type redisInfoResponse struct { 20 Addr string `json:"address"` 21 Info map[string]string `json:"info"` 22 RawInfo string `json:"raw_info"` 23 Cluster bool `json:"cluster"` 24 25 // Following fields are only set when connected to redis cluster. 26 RawClusterNodes string `json:"raw_cluster_nodes"` 27 QueueLocations []*queueLocationInfo `json:"queue_locations"` 28 } 29 30 type queueLocationInfo struct { 31 Queue string `json:"queue"` // queue name 32 KeySlot int64 `json:"keyslot"` // cluster key slot for the queue 33 Nodes []string `json:"nodes"` // list of cluster node addresses 34 } 35 36 func newRedisInfoHandlerFunc(client *redis.Client) http.HandlerFunc { 37 return func(w http.ResponseWriter, r *http.Request) { 38 res, err := client.Info(context.Background()).Result() 39 if err != nil { 40 http.Error(w, err.Error(), http.StatusInternalServerError) 41 return 42 } 43 info := parseRedisInfo(res) 44 resp := redisInfoResponse{ 45 Addr: client.Options().Addr, 46 Info: info, 47 RawInfo: res, 48 Cluster: false, 49 } 50 if err := json.NewEncoder(w).Encode(resp); err != nil { 51 http.Error(w, err.Error(), http.StatusInternalServerError) 52 return 53 } 54 } 55 } 56 57 func newRedisClusterInfoHandlerFunc(client *redis.ClusterClient, inspector *asynq.Inspector) http.HandlerFunc { 58 return func(w http.ResponseWriter, r *http.Request) { 59 ctx := context.Background() 60 rawClusterInfo, err := client.ClusterInfo(ctx).Result() 61 if err != nil { 62 http.Error(w, err.Error(), http.StatusInternalServerError) 63 return 64 } 65 info := parseRedisInfo(rawClusterInfo) 66 rawClusterNodes, err := client.ClusterNodes(ctx).Result() 67 if err != nil { 68 http.Error(w, err.Error(), http.StatusInternalServerError) 69 return 70 } 71 queues, err := inspector.Queues() 72 if err != nil { 73 http.Error(w, err.Error(), http.StatusInternalServerError) 74 return 75 } 76 var queueLocations []*queueLocationInfo 77 for _, qname := range queues { 78 q := queueLocationInfo{Queue: qname} 79 q.KeySlot, err = inspector.ClusterKeySlot(qname) 80 if err != nil { 81 http.Error(w, err.Error(), http.StatusInternalServerError) 82 return 83 } 84 nodes, err := inspector.ClusterNodes(qname) 85 if err != nil { 86 http.Error(w, err.Error(), http.StatusInternalServerError) 87 return 88 } 89 for _, n := range nodes { 90 q.Nodes = append(q.Nodes, n.Addr) 91 } 92 queueLocations = append(queueLocations, &q) 93 } 94 95 resp := redisInfoResponse{ 96 Addr: strings.Join(client.Options().Addrs, ","), 97 Info: info, 98 RawInfo: rawClusterInfo, 99 Cluster: true, 100 RawClusterNodes: rawClusterNodes, 101 QueueLocations: queueLocations, 102 } 103 if err := json.NewEncoder(w).Encode(resp); err != nil { 104 http.Error(w, err.Error(), http.StatusInternalServerError) 105 return 106 } 107 } 108 } 109 110 // Parses the return value from the INFO command. 111 // See https://redis.io/commands/info#return-value. 112 func parseRedisInfo(infoStr string) map[string]string { 113 info := make(map[string]string) 114 lines := strings.Split(infoStr, "\r\n") 115 for _, l := range lines { 116 kv := strings.Split(l, ":") 117 if len(kv) == 2 { 118 info[kv[0]] = kv[1] 119 } 120 } 121 return info 122 123 }