/** * @param Job $job * @param TaskResult $taskResult * @return TaskResult */ private function executeJobTask(Job $job, TaskResult $taskResult) { $stopwatchEvent = $this->stopwatch->start($taskResult->getId(), 'task'); $logger = new TaskLogger($job, $taskResult->getTask(), $this->storageApi); $logger->start($stopwatchEvent); $startTime = time(); try { $this->fillComponentData($taskResult); $httpClient = new Client(array(), $this->logger); $response = $httpClient->sendOrchestratorRequest($job, $taskResult->getTask(), $this->encryptor); $pollResponse = null; // handling async task if (ResponseValidator::isAsyncResponse($response)) { $taskJobUrl = null; try { $data = ResponseDecoder::decode($response); if (!empty($data['url'])) { $taskJobUrl = $data['url']; } } catch (\Exception $e) { } if ($taskJobUrl) { $taskResult->setJobUrl($taskJobUrl); $this->saveJobResult($this->jobResult); } $this->logTaskUsability($taskResult, $response); $retriesCount = 1; $timeout = $taskResult->getTimeoutMinutes() ? $taskResult->getTimeoutMinutes() : KeboolaOrchestratorBundle::TIMEOUT_MINUTES; // polling job do { $data = array('status' => 'unknown'); if (time() >= $startTime + $timeout * 60) { throw new Exception\JobRuntimeException(sprintf('Asynchronous task processing timeout after %d minutes', $timeout)); } $waitSeconds = min(pow(2, $retriesCount), 20); sleep($waitSeconds); try { $pollResponse = $httpClient->sendOrchestratorPollRequest($job, $response, $this->encryptor, $retriesCount); if ($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 } $retriesCount++; } while (array_key_exists('status', $data) && !StatusConverter::isFinishedStatus($data['status'])); } else { // stats log if (ResponseValidator::isSuccessfulResponse($response) || ResponseValidator::isInformationalResponse($response)) { $this->logTaskUsability($taskResult, $response); } } 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($pollResponse ? 'GET' : 'POST', $response->getHeaderLine(Client::EFFECTIVE_URL_HEADER_NAME)); $clientExc = new GuzzleException\ClientException('Error response from component', $fakeRequest, $response); throw $clientExc; } } if (!ResponseValidator::isSuccessfulResponse($response) && !ResponseValidator::isInformationalResponse($response)) { $fakeRequest = new Request($pollResponse ? 'GET' : 'POST', $response->getHeaderLine(Client::EFFECTIVE_URL_HEADER_NAME)); $clientExc = new GuzzleException\ClientException('Response with error HTTP code', $fakeRequest, $response); throw $clientExc; } $endEvent = $logger->end(); } catch (GuzzleException\ClientException $e) { $endEvent = $logger->clientError($e); if ($e->getResponse()) { $response = $e->getResponse(); } } catch (GuzzleException\BadResponseException $e) { $endEvent = $logger->responseError($e); if ($e->getResponse()) { $response = $e->getResponse(); } } catch (\Exception $e) { $endEvent = $logger->someError($e, $this->logger); $response = null; } $taskResult->setResult($endEvent, empty($response) ? null : $response); return $taskResult; }
/** * @param Phase $phase * @return Response[] */ public function startPhase(Phase $phase, PhaseLogger $logger, Client $httpClient) { /** * @var Response[] $jobResponses */ $jobResponses = array(); // create jobs foreach ($phase->getTasks() as $taskResult) { // skip inactive tasks if (!$taskResult->getTask()->getActive()) { continue; } $endEvent = null; try { $taskResult->setProcessingStatus(); $this->jobResult->addTaskResult($taskResult); $this->saveJobResult($this->jobResult); $stopwatchEvent = $this->stopwatch->start($taskResult->getId(), 'task'); $this->fillComponentData($taskResult); $logger->getLogger($taskResult)->start($stopwatchEvent); $response = $httpClient->sendOrchestratorRequest($phase->getJob(), $taskResult->getTask(), $this->encryptor); // if (!ResponseValidator::isAsyncResponse($response)) { // throw new UserException('Parallel task processing does not support synchronous components', null, array( // 'component' => $taskResult->getComponent(), // 'componentUrl' => $taskResult->getComponentUrl(), // 'action' => $taskResult->getAction(), // )); // } $taskJobUrl = null; try { $data = ResponseDecoder::decode($response); if (!empty($data['url'])) { $taskJobUrl = $data['url']; } } catch (\Exception $e) { } if ($taskJobUrl) { $taskResult->setJobUrl($taskJobUrl); $this->saveJobResult($this->jobResult); } if (count($phase->getTasks()) > 1) { $this->logParallelTaskUsability($taskResult, $response); } else { $this->logTaskUsability($taskResult, $response); } $jobResponses[$taskResult->getId()] = $response; } 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; } if ($endEvent) { $taskResult->setResult($endEvent, empty($response) ? null : $response); $this->saveJobResult($this->jobResult); } if ($taskResult->getError() && !$taskResult->getTask()->getContinueOnFailure()) { return false; } } return $jobResponses; }