/**
  * @param Exception $e the Exception that was thrown
  * @param string $command the command that was being executed
  * @param array $args the arguments of the command
  * @throws \Plista\Core\Redis\Exception
  * @return bool
  */
 private function handleException(Exception $e, $command, $args)
 {
     $excBrief = "{$e->getCode()}: {$e->getMessage()} ({$e->getFile()}:{$e->getLine()}) Stacktrace:\n" . $e->getTraceAsString();
     //		$excHash = md5($excBrief);
     //		$curTime = Registry::getSystem()->getTime()->current();
     //
     //		$this->excLog[$excHash]['count']++;
     //		$this->excLog[$excHash]['time'] = $curTime;
     // log the exception
     $this->log->warning("Caught Redis exception: {$excBrief}");
     if ($this->exceptionHandler) {
         // notify the handler and get the strategy
         $context = ExceptionContext::fromFunctionAndArguments($command, $args);
         $strategy = $this->exceptionHandler->handleException($e, $context);
     } else {
         // use the default strategy
         $strategy = $this->defaultHandlerStrategy;
     }
     // default is to discard the exception
     if (!$strategy) {
         $strategy = ExceptionStrategy::DISCARD();
     }
     // let's see what the handler wants us to do
     if ($strategy->equals(ExceptionStrategy::RETHROW)) {
         throw $e;
     }
     // this case is used by the FailoverWrapper
     if ($strategy->equals(ExceptionStrategy::RETURN_VALUE)) {
         return $strategy->returnValue;
     }
     // return false to signal failure. maybe interpreted by some callers as a valid value (which it
     // is in some cases), but that's not for us to worry about.
     return false;
 }
 /**
  * @param CoreException $e
  * @param ExceptionContext $ec
  * @return ExceptionStrategy
  * @throws FailoverException
  */
 public function handleException(CoreException $e, ExceptionContext $ec = null)
 {
     // we only want to handle ConnectionErrors
     if (!$e instanceof ConnectionError) {
         return ExceptionStrategy::RETHROW();
     }
     $this->log->warning(sprintf("Handling exception for connection %s: %s, trying to reconnect", $this->curConn->getUniqueId(), $e->getMessage()));
     if ($this->inMultiMode) {
         // usually we would throw an exception here, because data was lost, so the application should decide what to do.
         // ITE however wants us to just continue in this case as well, so we try to reset the multi mode and continue,
         // as if this were a regular error
         $this->log->warning(sprintf("connection error while multi mode was active, data was likely lost. msg: %s", $e->getMessage()));
         try {
             // we cannot use $this->curConn here as its a TCWrapper and would catch the exception directly, invoking this method
             // again and leading to a recursive loop of death
             $this->connections[$this->curConnKey]->getClient()->discard();
         } catch (Exception $e) {
             // we just drop the exception
         }
     }
     // disconnect first to reset the internal state in the instance, we set $force to true here,
     // in order to remove persistent connections as well
     $this->curConn->disconnect(true);
     // sleep for 50 ms to give the network a chance to restore itself
     usleep(50000);
     // try to reconnect once
     if (!$this->connectInstance($this->curConn)) {
         $this->log->warning("Reconnecting failed, deactivating connection");
         // not possible to reconnect, deactivate and continue
         $this->connections->deactivateConnection($this->curConnKey);
         $this->curConnKey = -1;
         $this->curConn = null;
     }
     // at this point either the old connection is active again, or we have to look for a new one
     if ($this->curConn === null) {
         $this->log->warning(sprintf("Trying to find new connection, configured connections: %s", $this->connections->getUniqueId()));
         // we need to find a functioning connection
         try {
             $this->activateNextConnection();
         } catch (FailoverException $foe) {
             // no more healthy connections, we catch the exception so we can link it to the original one
             throw new FailoverException("while handling a connection problem in the FailoverWrapper: " . $e->getMessage(), FailoverException::ERROR_NO_HEALTHY_CONNECTIONS, $e);
         }
     }
     $this->log->warning(sprintf("New connection %s active, reissuing command %s", $this->curConn->getUniqueId(), $ec->getFunction()));
     // at this point we (hopefully) have a functioning connection so we retry the command
     // TODO: this recursive call may lead to a very nasty deadlock, if a connection keeps breaking right after connecting
     // this is what the UNSTABLE status was used for. maybe instead of using $this, we should call directly on the connection object
     $retVal = call_user_func_array(array($this, $ec->getFunction()), $ec->getArguments());
     $strategy = ExceptionStrategy::RETURN_VALUE();
     $strategy->returnValue = $retVal;
     return $strategy;
 }