Overview

Namespaces

  • Contrib
    • Bundle
      • CoverallsBundle
        • Console
        • Entity
      • CoverallsV1Bundle
        • Api
        • Collector
        • Command
        • Config
        • Entity
          • Git
    • Component
      • File
      • Log
      • System
        • Git
  • Guzzle
    • Batch
      • Exception
    • Cache
    • Common
      • Exception
    • Http
      • Curl
      • Exception
      • Message
      • QueryAggregator
    • Inflection
    • Iterator
    • Log
    • Parser
      • Cookie
      • Message
      • UriTemplate
      • Url
    • Plugin
      • Async
      • Backoff
      • Cache
      • Cookie
        • CookieJar
        • Exception
      • CurlAuth
      • ErrorResponse
        • Exception
      • History
      • Log
      • Md5
      • Mock
      • Oauth
    • Service
      • Builder
      • Command
        • Factory
        • LocationVisitor
          • Request
          • Response
      • Description
      • Exception
      • Resource
    • Stream
  • PHP
  • Psr
    • Log
  • Symfony
    • Component
      • Config
        • Definition
          • Builder
          • Exception
        • Exception
        • Loader
        • Resource
        • Util
      • Console
        • Command
        • Formatter
        • Helper
        • Input
        • Output
        • Tester
      • EventDispatcher
        • Debug
      • Finder
        • Adapter
        • Comparator
        • Exception
        • Expression
        • Iterator
        • Shell
      • Stopwatch
      • Yaml
        • Exception

Classes

  • AbstractBackoffStrategy
  • AbstractErrorCodeBackoffStrategy
  • BackoffLogger
  • BackoffPlugin
  • CallbackBackoffStrategy
  • ConstantBackoffStrategy
  • CurlBackoffStrategy
  • ExponentialBackoffStrategy
  • HttpBackoffStrategy
  • LinearBackoffStrategy
  • ReasonPhraseBackoffStrategy
  • TruncatedBackoffStrategy

Interfaces

  • BackoffStrategyInterface
  • Overview
  • Namespace
  • Class
  • Tree
  • Todo
  1: <?php
  2: 
  3: namespace Guzzle\Plugin\Backoff;
  4: 
  5: use Guzzle\Common\Event;
  6: use Guzzle\Common\AbstractHasDispatcher;
  7: use Guzzle\Http\Message\EntityEnclosingRequestInterface;
  8: use Guzzle\Http\Message\RequestInterface;
  9: use Guzzle\Http\Message\Response;
 10: use Guzzle\Http\Curl\CurlMultiInterface;
 11: use Symfony\Component\EventDispatcher\EventSubscriberInterface;
 12: 
 13: /**
 14:  * Plugin to automatically retry failed HTTP requests using a backoff strategy
 15:  */
 16: class BackoffPlugin extends AbstractHasDispatcher implements EventSubscriberInterface
 17: {
 18:     const DELAY_PARAM = CurlMultiInterface::BLOCKING;
 19:     const RETRY_PARAM = 'plugins.backoff.retry_count';
 20:     const RETRY_EVENT = 'plugins.backoff.retry';
 21: 
 22:     /**
 23:      * @var BackoffStrategyInterface Backoff strategy
 24:      */
 25:     protected $strategy;
 26: 
 27:     /**
 28:      * @param BackoffStrategyInterface $strategy The backoff strategy used to determine whether or not to retry and
 29:      *                                           the amount of delay between retries.
 30:      */
 31:     public function __construct(BackoffStrategyInterface $strategy = null)
 32:     {
 33:         $this->strategy = $strategy;
 34:     }
 35: 
 36:     /**
 37:      * Retrieve a basic truncated exponential backoff plugin that will retry HTTP errors and cURL errors
 38:      *
 39:      * @param int   $maxRetries Maximum number of retries
 40:      * @param array $httpCodes  HTTP response codes to retry
 41:      * @param array $curlCodes  cURL error codes to retry
 42:      *
 43:      * @return self
 44:      */
 45:     public static function getExponentialBackoff(
 46:         $maxRetries = 3,
 47:         array $httpCodes = null,
 48:         array $curlCodes = null
 49:     ) {
 50:         return new self(new TruncatedBackoffStrategy($maxRetries,
 51:             new HttpBackoffStrategy($httpCodes,
 52:                 new CurlBackoffStrategy($curlCodes,
 53:                     new ExponentialBackoffStrategy()
 54:                 )
 55:             )
 56:         ));
 57:     }
 58: 
 59:     /**
 60:      * {@inheritdoc}
 61:      */
 62:     public static function getAllEvents()
 63:     {
 64:         return array(self::RETRY_EVENT);
 65:     }
 66: 
 67:     /**
 68:      * {@inheritdoc}
 69:      */
 70:     public static function getSubscribedEvents()
 71:     {
 72:         return array(
 73:             'request.sent'      => 'onRequestSent',
 74:             'request.exception' => 'onRequestSent',
 75:             CurlMultiInterface::POLLING_REQUEST => 'onRequestPoll'
 76:         );
 77:     }
 78: 
 79:     /**
 80:      * Called when a request has been sent  and isn't finished processing
 81:      *
 82:      * @param Event $event
 83:      */
 84:     public function onRequestSent(Event $event)
 85:     {
 86:         $request = $event['request'];
 87:         $response = $event['response'];
 88:         $exception = $event['exception'];
 89: 
 90:         $params = $request->getParams();
 91:         $retries = (int) $params->get(self::RETRY_PARAM);
 92:         $delay = $this->strategy->getBackoffPeriod($retries, $request, $response, $exception);
 93: 
 94:         if ($delay !== false) {
 95:             // Calculate how long to wait until the request should be retried
 96:             $params->set(self::RETRY_PARAM, ++$retries)
 97:                 ->set(self::DELAY_PARAM, microtime(true) + $delay);
 98:             // Send the request again
 99:             $request->setState(RequestInterface::STATE_TRANSFER);
100:             $this->dispatch(self::RETRY_EVENT, array(
101:                 'request'  => $request,
102:                 'response' => $response,
103:                 'handle'   => $exception ? $exception->getCurlHandle() : null,
104:                 'retries'  => $retries,
105:                 'delay'    => $delay
106:             ));
107:         }
108:     }
109: 
110:     /**
111:      * Called when a request is polling in the curl multi object
112:      *
113:      * @param Event $event
114:      */
115:     public function onRequestPoll(Event $event)
116:     {
117:         $request = $event['request'];
118:         $delay = $request->getParams()->get(self::DELAY_PARAM);
119: 
120:         // If the duration of the delay has passed, retry the request using the pool
121:         if (null !== $delay && microtime(true) >= $delay) {
122:             // Remove the request from the pool and then add it back again. This is required for cURL to know that we
123:             // want to retry sending the easy handle.
124:             $request->getParams()->remove(self::DELAY_PARAM);
125:             // Rewind the request body if possible
126:             if ($request instanceof EntityEnclosingRequestInterface && $request->getBody()) {
127:                 $request->getBody()->seek(0);
128:             }
129:             $multi = $event['curl_multi'];
130:             $multi->remove($request);
131:             $multi->add($request);
132:         }
133:     }
134: }
135: 
php-coveralls API documentation generated by ApiGen 2.8.0