Guzzle batch job fails mid-execution due to token expiry

No idea why this is happening, my Laravel job keeps dying partway through a large data export. I cache the access token at the start of the process, but by the time Guzzle hits the third batch of /api/v2/analytics/conversations/summary requests, the server returns a 401 Unauthorized because the token has expired. My refresh logic only triggers on initial auth, so I’m looking for the best pattern to handle mid-request token rotation without breaking the queue.

It depends, but generally you should never cache a static token for long-running Laravel jobs. Genesys Cloud tokens expire in 60 minutes. If your export takes longer, you get 401s. The fix is to use a Guzzle middleware that intercepts 401 responses, triggers a refresh, and retries the failed request automatically. Do not rely on job-level token caching.

Here is the middleware pattern using guzzlehttp/oauth-subscriber or a custom handler. This example uses a simple closure middleware for clarity. Ensure your platformClient or auth service supports async token refresh.

use GuzzleHttp\Middleware;
use GuzzleHttp\HandlerStack;

function createGenesysMiddleware(AuthService $authService) {
 return function (callable $handler) use ($authService) {
 return function ($request, $options) use ($handler, $authService) {
 return $handler($request, $options)->then(
 function ($response) {
 return $response;
 },
 function ($exception) use ($handler, $request, $options, $authService) {
 if ($exception instanceof \GuzzleHttp\Exception\ClientException) {
 $response = $exception->getResponse();
 if ($response->getStatusCode() == 401) {
 // Refresh token
 $newToken = $authService->refreshToken();
 
 // Update request headers
 $request = $request->withHeader('Authorization', 'Bearer ' . $newToken);
 
 // Retry once
 return $handler($request, $options);
 }
 }
 throw $exception;
 }
 );
 };
 };
}

// Usage in your Laravel Job
$handlerStack = HandlerStack::create();
$handlerStack->push(createGenesysMiddleware(app(AuthService::class)));

$client = new \GuzzleHttp\Client([
 'handler' => $handlerStack,
 'base_uri' => 'https://api.mypurecloud.com',
 'headers' => [
 'Authorization' => 'Bearer ' . $authService->getToken(),
 'Content-Type' => 'application/json'
 ]
]);

// Now fetch analytics endpoints safely. The middleware handles retries.

Environment:

Component Version/Note
Guzzle 7.x
Laravel 10+
Auth Service Must support refreshToken()

This ensures your queue jobs survive token expiry without manual intervention. Keep the token refresh logic thread-safe if using multiple workers.