How can I get Guzzle 6 to retry a request upon a 503 error in Laravel

ZeroGodForce picture ZeroGodForce · Feb 8, 2016 · Viewed 11.2k times · Source

I've written some code in Laravel 5.2 to retrieve results from an unrelible API source. However, it needs to be able to automatically retry the request on failed attempts, as the API call results in a 503 about a third of the time.

I'm use Guzzle to do this, and I think I know where to put the code that will intercept the 503 responses before they are processed; but I'm not sure what to actually write there.

The guzzle documentation doesn't offer much as far as retries go, and all of the examples I've come across of Guzzle 6 only show how to retrieve results (which I can already do), but not how to get it to repeat the request if needed.

I'm by no means asking anyone to do the work for me - but I think I'm approaching the limits of my understanding on this. If anybody can point me in the right direction, it'd be much appreciated :)

EDIT:

I will try and revise. Please consider the following code. In it, I want to send a GET request which should normally yield a JSON response.

DataController.php

$client = new \GuzzleHttp\Client();
$request = $client->request('GET', 'https://httpbin.org/status/503'); // URI is for testing purposes

When the response from this request is a 503, I can intercept it here:

Handler.php

public function render($request, Exception $e)
{
  if ($e->getCode() == 503)
  {
    // Code that would tell Guzzle to retry the request 5 times with a 10s delay before failing completely
  }

  return parent::render($request, $e);
}

I don't know that that is the best place to put it, but the real problem is I don't know is what to write inside the if ($e->getCode() == 503)

Answer

Logan Bailey picture Logan Bailey · Feb 9, 2016

Guzzle by default throws exceptions when a non 2** response is returned. In your case you're seeing a 503 response. Exceptions can be thought of as errors that the application can recover from. The way this works is with try catch blocks.

try {
    // The code that can throw an exception will go here
    throw new \Exception('A generic error');
    // code from here down won't be executed, because the exception was thrown.
} catch (\Exception $e) {
    // Handle the exception in the best manner possible.
}

You wrap the code that could throw an exception in the try portion of the block. Then you add your error handling code in the catch portion of the block. You can read the above link for more information on how php handles exceptions.

For your case, lets move the Guzzle call to it's own method in your controller:

public function performLookUp($retryOnError = false)
{
    try {
        $client = new \GuzzleHttp\Client();
        $request = $client->request('GET', 'https://httpbin.org/status/503'); 
        return $request->send();
    } catch (\GuzzleHttp\Exception\BadResponseException $e) {
        if ($retryOnError) {
            return $this->performLookUp();
        }
        abort(503);
   }
}

Now in your controller you can execute, $this->performLookUp(true);.