/**
  * @param TaskResult $taskResult
  * @return TaskLogger
  */
 public function getLogger(TaskResult $taskResult)
 {
     $taskExists = false;
     foreach ($this->phase->getTasks() as $task) {
         if ($task->getId() !== $taskResult->getId()) {
             continue;
         }
         $taskExists = true;
     }
     if (!$taskExists) {
         throw new \InvalidArgumentException('Non existing task given');
     }
     if (!array_key_exists($taskResult->getId(), $this->loggers)) {
         $this->loggers[$taskResult->getId()] = new TaskLogger($this->phase->getJob(), $taskResult->getTask(), $this->storageApi);
     }
     return $this->loggers[$taskResult->getId()];
 }
 /**
  * @param Phase $phase
  * @param PhaseLogger $logger
  * @param Client $httpClient
  * @param Response[] $jobResponses
  * @return array|bool
  */
 public function pollPhase(Phase $phase, PhaseLogger $logger, Client $httpClient, $jobResponses = array())
 {
     /**
      * @var Response[] $pollResponses
      */
     $pollResponses = array();
     /**
      * @var TaskResult[] $taskResults
      */
     $taskResults = array();
     foreach ($phase->getTasks() as $taskResult) {
         $taskResults[$taskResult->getId()] = $taskResult;
     }
     // all jobs polling
     $retriesCount = 1;
     $errorsCount = 0;
     do {
         $waitSeconds = min(pow(2, $retriesCount), 20);
         sleep($waitSeconds);
         foreach ($jobResponses as $key => $jobResponse) {
             $taskResult = $taskResults[$key];
             $startTime = $taskResult->getStartTime()->getTimestamp();
             try {
                 $pollResponse = null;
                 $timeout = $taskResult->getTimeoutMinutes() ? $taskResult->getTimeoutMinutes() : KeboolaOrchestratorBundle::TIMEOUT_MINUTES;
                 $data = array('status' => 'unknown');
                 if (time() >= $startTime + $timeout * 60) {
                     throw new Exception\JobRuntimeException(sprintf('Asynchronous task processing timeout after %d minutes', $timeout));
                 }
                 try {
                     $pollResponse = $httpClient->sendOrchestratorPollRequest($phase->getJob(), $jobResponse, $this->encryptor, $retriesCount);
                     if ($pollResponse) {
                         $pollResponses[$key] = $pollResponse;
                         $data = ResponseDecoder::decode($pollResponse);
                     }
                 } catch (GuzzleException\RequestException $e) {
                     if ($e instanceof Exception\CurlException) {
                     } else {
                         $prevE = $e->getPrevious();
                         if (!$prevE || !$prevE instanceof Exception\JobRuntimeException) {
                             throw $e;
                         }
                     }
                 } catch (\Exception $e) {
                     // maybe json decode error, do nothing
                 }
                 if (!array_key_exists('status', $data)) {
                     continue;
                 }
                 if (!StatusConverter::isFinishedStatus($data['status'])) {
                     continue;
                 }
                 if ($pollResponse) {
                     $response = $pollResponse;
                     if (empty($data) || !in_array($data['status'], array('success', 'ok'))) {
                         //@TODO logovat odpovedi, ktere vraci nesmyslne OK status
                         $fakeRequest = new Request('GET', $response->getHeaderLine(Client::EFFECTIVE_URL_HEADER_NAME));
                         $clientExc = new GuzzleException\ClientException('Error response from component', $fakeRequest, $response);
                         throw $clientExc;
                     }
                 }
                 if (!ResponseValidator::isSuccessfulResponse($pollResponse) && !ResponseValidator::isInformationalResponse($pollResponse)) {
                     $fakeRequest = new Request('GET', $pollResponse->getHeaderLine(Client::EFFECTIVE_URL_HEADER_NAME));
                     $clientExc = new GuzzleException\ClientException('Response with error HTTP code', $fakeRequest, $pollResponse);
                     throw $clientExc;
                 }
                 $endEvent = $logger->getLogger($taskResult)->end();
             } catch (GuzzleException\ClientException $e) {
                 $endEvent = $logger->getLogger($taskResult)->clientError($e);
                 if ($e->getResponse()) {
                     $response = $e->getResponse();
                 }
             } catch (GuzzleException\BadResponseException $e) {
                 $endEvent = $logger->getLogger($taskResult)->responseError($e);
                 if ($e->getResponse()) {
                     $response = $e->getResponse();
                 }
             } catch (\Exception $e) {
                 $endEvent = $logger->getLogger($taskResult)->someError($e, $this->logger);
                 $response = null;
             }
             $taskResult->setResult($endEvent, empty($response) ? null : $response);
             if ($taskResult->getError() && !$taskResult->getTask()->getContinueOnFailure()) {
                 $errorsCount++;
             }
             unset($jobResponses[$key]);
         }
         $this->saveJobResult($this->jobResult);
         $retriesCount++;
     } while (count($jobResponses));
     if ($errorsCount) {
         return false;
     }
     return array();
 }