public function execute()
{
$this->prepare();
$metrics = $this->getMetrics();
$cacheEnabled = $this->isRequestCacheEnabled();
// always adding the command to request log
$this->recordExecutedCommand();
// trying from cache first
if ($cacheEnabled) {
$cacheHit = $this->requestCache->exists($this->getCommandKey(), $this->getCacheKey());
if ($cacheHit) {
$metrics->markResponseFromCache();
$this->recordExecutionEvent(self::EVENT_RESPONSE_FROM_CACHE);
return $this->requestCache->get($this->getCommandKey(), $this->getCacheKey());
}
}
$circuitBreaker = $this->getCircuitBreaker();
if (!$circuitBreaker->allowRequest()) {
$metrics->markShortCircuited();
$this->recordExecutionEvent(self::EVENT_SHORT_CIRCUITED);
return $this->getFallbackOrThrowException();
}
$this->invocationStartTime = $this->getTimeInMilliseconds();
try {
$result = $this->run();
$this->recordExecutionTime();
$metrics->markSuccess();
$circuitBreaker->markSuccess();
$this->recordExecutionEvent(self::EVENT_SUCCESS);
} catch (BadRequestException $exception) {
// Treated differently and allowed to propagate without any stats tracking or fallback logic
$this->recordExecutionTime();
throw $exception;
} catch (Exception $exception) {
$this->recordExecutionTime();
$metrics->markFailure();
$this->executionException = $exception;
$this->recordExecutionEvent(self::EVENT_FAILURE);
$result = $this->getFallbackOrThrowException($exception);
}
// putting the result into cache
if ($cacheEnabled) {
$this->requestCache->put($this->getCommandKey(), $this->getCacheKey(), $result);
}
return $result;
}