func (c *ClusterClient) Process(cmd Cmder) error { slot, node, err := c.cmdSlotAndNode(cmd) if err != nil { cmd.setErr(err) return err } var ask bool for attempt := 0; attempt <= c.opt.MaxRedirects; attempt++ { if attempt > 0 { cmd.reset() } if ask { pipe := node.Client.Pipeline() pipe.Process(NewCmd("ASKING")) pipe.Process(cmd) _, _ = pipe.Exec() pipe.Close() ask = false } else { node.Client.Process(cmd) } // If there is no (real) error, we are done! err := cmd.Err() if err == nil { return nil } // On network errors try random node. if errors.IsRetryable(err) { node, err = c.randomNode() continue } var moved bool var addr string moved, ask, addr = errors.IsMoved(err) if moved || ask { master, _ := c.slotMasterNode(slot) if moved && (master == nil || master.Client.getAddr() != addr) { c.lazyReloadSlots() } node, err = c.nodeByAddr(addr) if err != nil { cmd.setErr(err) return err } continue } break } return cmd.Err() }
func (c *ClusterClient) execClusterCmds( cn *pool.Conn, cmds []Cmder, failedCmds map[*clusterNode][]Cmder, ) (map[*clusterNode][]Cmder, error) { if err := writeCmd(cn, cmds...); err != nil { setCmdsErr(cmds, err) return failedCmds, err } var retErr error setRetErr := func(err error) { if retErr == nil { retErr = err } } for i, cmd := range cmds { err := cmd.readReply(cn) if err == nil { continue } if errors.IsNetwork(err) { cmd.reset() failedCmds[nil] = append(failedCmds[nil], cmds[i:]...) break } else if moved, ask, addr := errors.IsMoved(err); moved { c.lazyReloadSlots() cmd.reset() node, err := c.nodeByAddr(addr) if err != nil { setRetErr(err) continue } failedCmds[node] = append(failedCmds[node], cmd) } else if ask { cmd.reset() node, err := c.nodeByAddr(addr) if err != nil { setRetErr(err) continue } failedCmds[node] = append(failedCmds[node], NewCmd("ASKING"), cmd) } else { setRetErr(err) } } return failedCmds, retErr }