Google_Task_Runner

A task runner with exponential backoff support.

Defined (1)

The class is defined in the following location(s).

/vendor/google/apiclient/src/Google/Task/Runner.php  
  1. class Google_Task_Runner 
  2. /** 
  3. * @var integer $maxDelay The max time (in seconds) to wait before a retry. 
  4. */ 
  5. private $maxDelay = 60; 
  6. /** 
  7. * @var integer $delay The previous delay from which the next is calculated. 
  8. */ 
  9. private $delay = 1; 
  10.  
  11. /** 
  12. * @var integer $factor The base number for the exponential back off. 
  13. */ 
  14. private $factor = 2; 
  15. /** 
  16. * @var float $jitter A random number between -$jitter and $jitter will be 
  17. * added to $factor on each iteration to allow for a better distribution of 
  18. * retries. 
  19. */ 
  20. private $jitter = 0.5; 
  21.  
  22. /** 
  23. * @var integer $attempts The number of attempts that have been tried so far. 
  24. */ 
  25. private $attempts = 0; 
  26. /** 
  27. * @var integer $maxAttempts The max number of attempts allowed. 
  28. */ 
  29. private $maxAttempts = 1; 
  30.  
  31. /** 
  32. * @var Google_Client $client The current API client. 
  33. */ 
  34. private $client; 
  35.  
  36. /** 
  37. * @var string $name The name of the current task (used for logging). 
  38. */ 
  39. private $name; 
  40. /** 
  41. * @var callable $action The task to run and possibly retry. 
  42. */ 
  43. private $action; 
  44. /** 
  45. * @var array $arguments The task arguments. 
  46. */ 
  47. private $arguments; 
  48.  
  49. /** 
  50. * Creates a new task runner with exponential backoff support. 
  51. * @param Google_Client $client The current API client 
  52. * @param string $name The name of the current task (used for logging) 
  53. * @param callable $action The task to run and possibly retry 
  54. * @param array $arguments The task arguments 
  55. * @throws Google_Task_Exception when misconfigured 
  56. */ 
  57. public function __construct( 
  58. Google_Client $client,  
  59. $name,  
  60. $action,  
  61. array $arguments = array() 
  62. ) { 
  63. $config = (array) $client->getClassConfig('Google_Task_Runner'); 
  64.  
  65. if (isset($config['initial_delay'])) { 
  66. if ($config['initial_delay'] < 0) { 
  67. throw new Google_Task_Exception( 
  68. 'Task configuration `initial_delay` must not be negative.' 
  69. ); 
  70.  
  71. $this->delay = $config['initial_delay']; 
  72.  
  73. if (isset($config['max_delay'])) { 
  74. if ($config['max_delay'] <= 0) { 
  75. throw new Google_Task_Exception( 
  76. 'Task configuration `max_delay` must be greater than 0.' 
  77. ); 
  78.  
  79. $this->maxDelay = $config['max_delay']; 
  80.  
  81. if (isset($config['factor'])) { 
  82. if ($config['factor'] <= 0) { 
  83. throw new Google_Task_Exception( 
  84. 'Task configuration `factor` must be greater than 0.' 
  85. ); 
  86.  
  87. $this->factor = $config['factor']; 
  88.  
  89. if (isset($config['jitter'])) { 
  90. if ($config['jitter'] <= 0) { 
  91. throw new Google_Task_Exception( 
  92. 'Task configuration `jitter` must be greater than 0.' 
  93. ); 
  94.  
  95. $this->jitter = $config['jitter']; 
  96.  
  97. if (isset($config['retries'])) { 
  98. if ($config['retries'] < 0) { 
  99. throw new Google_Task_Exception( 
  100. 'Task configuration `retries` must not be negative.' 
  101. ); 
  102. $this->maxAttempts += $config['retries']; 
  103.  
  104. if (!is_callable($action)) { 
  105. throw new Google_Task_Exception( 
  106. 'Task argument `$action` must be a valid callable.' 
  107. ); 
  108.  
  109. $this->name = $name; 
  110. $this->client = $client; 
  111. $this->action = $action; 
  112. $this->arguments = $arguments; 
  113.  
  114. /** 
  115. * Checks if a retry can be attempted. 
  116. * @return boolean 
  117. */ 
  118. public function canAttmpt() 
  119. return $this->attempts < $this->maxAttempts; 
  120.  
  121. /** 
  122. * Runs the task and (if applicable) automatically retries when errors occur. 
  123. * @return mixed 
  124. * @throws Google_Task_Retryable on failure when no retries are available. 
  125. */ 
  126. public function run() 
  127. while ($this->attempt()) { 
  128. try { 
  129. return call_user_func_array($this->action, $this->arguments); 
  130. } catch (Google_Task_Retryable $exception) { 
  131. $allowedRetries = $exception->allowedRetries(); 
  132.  
  133. if (!$this->canAttmpt() || !$allowedRetries) { 
  134. throw $exception; 
  135.  
  136. if ($allowedRetries > 0) { 
  137. $this->maxAttempts = min( 
  138. $this->maxAttempts,  
  139. $this->attempts + $allowedRetries 
  140. ); 
  141.  
  142. /** 
  143. * Runs a task once, if possible. This is useful for bypassing the `run()` 
  144. * loop. 
  145. * NOTE: If this is not the first attempt, this function will sleep in 
  146. * accordance to the backoff configurations before running the task. 
  147. * @return boolean 
  148. */ 
  149. public function attempt() 
  150. if (!$this->canAttmpt()) { 
  151. return false; 
  152.  
  153. if ($this->attempts > 0) { 
  154. $this->backOff(); 
  155.  
  156. $this->attempts++; 
  157. return true; 
  158.  
  159. /** 
  160. * Sleeps in accordance to the backoff configurations. 
  161. */ 
  162. private function backOff() 
  163. $delay = $this->getDelay(); 
  164.  
  165. $this->client->getLogger()->debug( 
  166. 'Retrying task with backoff',  
  167. array( 
  168. 'request' => $this->name,  
  169. 'retry' => $this->attempts,  
  170. 'backoff_seconds' => $delay 
  171. ); 
  172.  
  173. usleep($delay * 1000000); 
  174.  
  175. /** 
  176. * Gets the delay (in seconds) for the current backoff period. 
  177. * @return float 
  178. */ 
  179. private function getDelay() 
  180. $jitter = $this->getJitter(); 
  181. $factor = $this->attempts > 1 ? $this->factor + $jitter : 1 + abs($jitter); 
  182.  
  183. return $this->delay = min($this->maxDelay, $this->delay * $factor); 
  184.  
  185. /** 
  186. * Gets the current jitter (random number between -$this->jitter and 
  187. * $this->jitter). 
  188. * @return float 
  189. */ 
  190. private function getJitter() 
  191. return $this->jitter * 2 * mt_rand() / mt_getrandmax() - $this->jitter;