| 961 | } |
| 962 | |
| 963 | func (c *clusterState) slotClosestNode(slot int) (*clusterNode, error) { |
| 964 | nodes := c.slotNodes(slot) |
| 965 | if len(nodes) == 0 { |
| 966 | return c.nodes.Random() |
| 967 | } |
| 968 | |
| 969 | allNodesFailing := true |
| 970 | var ( |
| 971 | closestNonFailingNode *clusterNode |
| 972 | closestNode *clusterNode |
| 973 | minLatency time.Duration |
| 974 | ) |
| 975 | |
| 976 | // setting the max possible duration as zerovalue for minlatency |
| 977 | minLatency = time.Duration(math.MaxInt64) |
| 978 | |
| 979 | for _, n := range nodes { |
| 980 | if closestNode == nil || n.Latency() < minLatency { |
| 981 | closestNode = n |
| 982 | minLatency = n.Latency() |
| 983 | if !n.Failing() { |
| 984 | closestNonFailingNode = n |
| 985 | allNodesFailing = false |
| 986 | } |
| 987 | } |
| 988 | } |
| 989 | |
| 990 | // pick the healthly node with the lowest latency |
| 991 | if !allNodesFailing && closestNonFailingNode != nil { |
| 992 | return closestNonFailingNode, nil |
| 993 | } |
| 994 | |
| 995 | // if all nodes are failing, we will pick the temporarily failing node with lowest latency |
| 996 | if minLatency < maximumNodeLatency && closestNode != nil { |
| 997 | internal.Logger.Printf(context.TODO(), "redis: all nodes are marked as failed, picking the temporarily failing node with lowest latency") |
| 998 | return closestNode, nil |
| 999 | } |
| 1000 | |
| 1001 | // If all nodes are having the maximum latency(all pings are failing) - return a random node across the cluster |
| 1002 | internal.Logger.Printf(context.TODO(), "redis: pings to all nodes are failing, picking a random node across the cluster") |
| 1003 | return c.nodes.Random() |
| 1004 | } |
| 1005 | |
| 1006 | func (c *clusterState) slotRandomNode(slot int) (*clusterNode, error) { |
| 1007 | nodes := c.slotNodes(slot) |