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 *baseClient) Process(cmd Cmder) error { for i := 0; i <= c.opt.MaxRetries; i++ { if i > 0 { cmd.reset() } cn, err := c.conn() if err != nil { cmd.setErr(err) return err } readTimeout := cmd.readTimeout() if readTimeout != nil { cn.ReadTimeout = *readTimeout } else { cn.ReadTimeout = c.opt.ReadTimeout } cn.WriteTimeout = c.opt.WriteTimeout if err := writeCmd(cn, cmd); err != nil { c.putConn(cn, err, false) cmd.setErr(err) if err != nil && errors.IsRetryable(err) { continue } return err } err = cmd.readReply(cn) c.putConn(cn, err, readTimeout != nil) if err != nil && errors.IsRetryable(err) { continue } return err } return cmd.Err() }
func execCmds(cn *pool.Conn, cmds []Cmder) ([]Cmder, error) { if err := writeCmd(cn, cmds...); err != nil { setCmdsErr(cmds, err) return cmds, err } var firstCmdErr error var failedCmds []Cmder for _, cmd := range cmds { err := cmd.readReply(cn) if err == nil { continue } if firstCmdErr == nil { firstCmdErr = err } if errors.IsRetryable(err) { failedCmds = append(failedCmds, cmd) } } return failedCmds, firstCmdErr }