1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85: 86: 87: 88: 89: 90: 91: 92: 93: 94: 95: 96: 97: 98: 99: 100: 101: 102: 103: 104: 105: 106: 107: 108: 109: 110: 111: 112: 113: 114: 115: 116: 117: 118: 119: 120: 121: 122: 123: 124: 125: 126: 127:
<?php
namespace Guzzle\Plugin\Backoff;
use Guzzle\Common\Event;
use Guzzle\Common\AbstractHasDispatcher;
use Guzzle\Http\Message\EntityEnclosingRequestInterface;
use Guzzle\Http\Message\RequestInterface;
use Guzzle\Http\Curl\CurlMultiInterface;
use Guzzle\Http\Exception\CurlException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
class BackoffPlugin extends AbstractHasDispatcher implements EventSubscriberInterface
{
const DELAY_PARAM = CurlMultiInterface::BLOCKING;
const RETRY_PARAM = 'plugins.backoff.retry_count';
const RETRY_EVENT = 'plugins.backoff.retry';
protected $strategy;
public function __construct(BackoffStrategyInterface $strategy = null)
{
$this->strategy = $strategy;
}
public static function getExponentialBackoff(
$maxRetries = 3,
array $httpCodes = null,
array $curlCodes = null
) {
return new self(new TruncatedBackoffStrategy($maxRetries,
new HttpBackoffStrategy($httpCodes,
new CurlBackoffStrategy($curlCodes,
new ExponentialBackoffStrategy()
)
)
));
}
public static function getAllEvents()
{
return array(self::RETRY_EVENT);
}
public static function getSubscribedEvents()
{
return array(
'request.sent' => 'onRequestSent',
'request.exception' => 'onRequestSent',
CurlMultiInterface::POLLING_REQUEST => 'onRequestPoll'
);
}
public function onRequestSent(Event $event)
{
$request = $event['request'];
$response = $event['response'];
$exception = $event['exception'];
$params = $request->getParams();
$retries = (int) $params->get(self::RETRY_PARAM);
$delay = $this->strategy->getBackoffPeriod($retries, $request, $response, $exception);
if ($delay !== false) {
$params->set(self::RETRY_PARAM, ++$retries)
->set(self::DELAY_PARAM, microtime(true) + $delay);
$request->setState(RequestInterface::STATE_TRANSFER);
$this->dispatch(self::RETRY_EVENT, array(
'request' => $request,
'response' => $response,
'handle' => ($exception && $exception instanceof CurlException) ? $exception->getCurlHandle() : null,
'retries' => $retries,
'delay' => $delay
));
}
}
public function onRequestPoll(Event $event)
{
$request = $event['request'];
$delay = $request->getParams()->get(self::DELAY_PARAM);
if (null !== $delay && microtime(true) >= $delay) {
$request->getParams()->remove(self::DELAY_PARAM);
if ($request instanceof EntityEnclosingRequestInterface && $request->getBody()) {
$request->getBody()->seek(0);
}
$multi = $event['curl_multi'];
$multi->remove($request);
$multi->add($request);
}
}
}