1: <?php
2:
3: namespace Guzzle\Plugin\Backoff;
4:
5: use Guzzle\Http\Message\RequestInterface;
6: use Guzzle\Http\Message\Response;
7: use Guzzle\Http\Exception\HttpException;
8:
9: /**
10: * Abstract backoff strategy that allows for a chain of responsibility
11: */
12: abstract class AbstractBackoffStrategy implements BackoffStrategyInterface
13: {
14: /**
15: * @var AbstractBackoffStrategy Next strategy in the chain
16: */
17: protected $next;
18:
19: /**
20: * @param AbstractBackoffStrategy $next Next strategy in the chain
21: */
22: public function setNext(AbstractBackoffStrategy $next)
23: {
24: $this->next = $next;
25: }
26:
27: /**
28: * Get the next backoff strategy in the chain
29: *
30: * @return AbstractBackoffStrategy|null
31: */
32: public function getNext()
33: {
34: return $this->next;
35: }
36:
37: /**
38: * {@inheritdoc}
39: */
40: public function getBackoffPeriod(
41: $retries,
42: RequestInterface $request,
43: Response $response = null,
44: HttpException $e = null
45: ) {
46: $delay = $this->getDelay($retries, $request, $response, $e);
47: if ($delay === false) {
48: // The strategy knows that this must not be retried
49: return false;
50: } elseif ($delay === null) {
51: // If the strategy is deferring a decision and the next strategy will not make a decision then return false
52: return !$this->next || !$this->next->makesDecision()
53: ? false
54: : $this->next->getBackoffPeriod($retries, $request, $response, $e);
55: } elseif ($delay === true) {
56: // if the strategy knows that it must retry but is deferring to the next to determine the delay
57: if (!$this->next) {
58: return 0;
59: } else {
60: $next = $this->next;
61: while ($next->makesDecision() && $next->getNext()) {
62: $next = $next->getNext();
63: }
64: return !$next->makesDecision() ? $next->getBackoffPeriod($retries, $request, $response, $e) : 0;
65: }
66: } else {
67: return $delay;
68: }
69: }
70:
71: /**
72: * Check if the strategy does filtering and makes decisions on whether or not to retry.
73: *
74: * Strategies that return false will never retry if all of the previous strategies in a chain defer on a backoff
75: * decision.
76: *
77: * @return bool
78: */
79: abstract public function makesDecision();
80:
81: /**
82: * Implement the concrete strategy
83: *
84: * @param int $retries Number of retries of the request
85: * @param RequestInterface $request Request that was sent
86: * @param Response $response Response that was received. Note that there may not be a response
87: * @param HttpException $e Exception that was encountered if any
88: *
89: * @return bool|int|null Returns false to not retry or the number of seconds to delay between retries. Return true
90: * or null to defer to the next strategy if available, and if not, return 0.
91: */
92: abstract protected function getDelay(
93: $retries,
94: RequestInterface $request,
95: Response $response = null,
96: HttpException $e = null
97: );
98: }
99: