Installation:
composer require hyperf/guzzle
Ensure your Laravel app uses Swoole (e.g., spatie/laravel-swoole) or Hyperf for coroutine support.
Basic Usage:
Register the Guzzle client in Laravel’s service container (e.g., AppServiceProvider):
use Hyperf\Guzzle\ClientFactory;
use Illuminate\Support\ServiceProvider;
public function register()
{
$this->app->singleton(ClientFactory::class, function ($app) {
return new ClientFactory(config('guzzle'));
});
}
First Use Case: Fetch data asynchronously in a coroutine:
use Hyperf\Guzzle\ClientFactory;
use Swoole\Coroutine;
Coroutine::create(function () {
$client = app(ClientFactory::class)->create();
$response = $client->get('https://httpbin.org/get');
$data = json_decode($response->getBody(), true);
// Process data (e.g., store in DB, dispatch event)
});
Configuration: Publish the config file:
php artisan vendor:publish --provider="Hyperf\Guzzle\GuzzleServiceProvider" --tag="config"
Update config/guzzle.php for timeouts, middleware, etc.
Use Swoole\Coroutine for non-blocking requests:
Coroutine::create(function () {
$client = app(ClientFactory::class)->create();
$response = $client->request('POST', 'https://api.example.com/webhook', [
'json' => ['event' => 'order_created'],
]);
// Handle response
});
Attach Guzzle middleware (e.g., retries, auth) via config:
// config/guzzle.php
'middleware' => [
\Hyperf\Guzzle\Middleware\RetryMiddleware::class,
\GuzzleHttp\Middleware::tap(function ($request) {
$request = $request->withHeader('Authorization', 'Bearer ' . config('services.api.token'));
return $request;
}),
],
Execute multiple HTTP calls concurrently:
$coroutines = [];
foreach ($urls as $url) {
$coroutines[] = Coroutine::create(function () use ($url) {
$client = app(ClientFactory::class)->create();
return $client->get($url);
});
}
Coroutine::wait($coroutines); // Wait for all to complete
Offload async HTTP calls to Laravel queues (using Swoole workers):
use Hyperf\Guzzle\ClientFactory;
use Illuminate\Bus\Queueable;
use Illuminate\Contracts\Queue\ShouldQueue;
use Illuminate\Foundation\Bus\Dispatchable;
use Illuminate\Queue\InteractsWithQueue;
class AsyncApiCall implements ShouldQueue
{
use Dispatchable, InteractsWithQueue, Queueable;
public function handle()
{
Coroutine::create(function () {
$client = app(ClientFactory::class)->create();
$response = $client->get('https://api.example.com/data');
// Process and store results
});
}
}
Use Guzzle’s exception handling with coroutines:
try {
Coroutine::create(function () {
$client = app(ClientFactory::class)->create();
$response = $client->get('https://api.example.com/fail');
})->throw(); // Re-throw coroutine exceptions
} catch (\GuzzleHttp\Exception\RequestException $e) {
report($e);
// Retry or fallback logic
}
Mock coroutines in tests (e.g., PHPUnit):
use Swoole\Coroutine;
public function testAsyncCall()
{
Coroutine::create(function () {
// Test coroutine logic
});
// Simulate coroutine completion (e.g., via events or callbacks)
}
Blocking Calls in Coroutines
file_get_contents(), sleep()) inside a coroutine will freeze the entire Swoole worker.Swoole\Coroutine::yield() or offload to a separate coroutine.Global State in Coroutines
Laravel Facade Conflicts
Http facade may not work with hyperf/guzzle directly.class CoroutineHttpClient {
public static function get($url) {
return Coroutine::create(function () use ($url) {
$client = app(ClientFactory::class)->create();
return $client->get($url);
});
}
}
Timeout Misconfiguration
config/guzzle.php:
'timeout' => 10.0, // seconds
'connect_timeout' => 2.0,
Database Deadlocks
pdo_swoole) or release connections explicitly.Middleware Order
config/guzzle.php.Coroutine Leaks
Swoole\Coroutine::stats() to monitor active coroutines:
$stats = Swoole\Coroutine::stats();
dump($stats['running_num'], $stats['total_num']);
Logging Coroutine IDs
\Log::debug('Coroutine ID: ' . Swoole\Coroutine::getuid());
Timeout Debugging
$client = app(ClientFactory::class)->create([
'debug' => true,
]);
Testing Async Code
Swoole\Coroutine::wait() to simulate async completion in tests:
$coroutine = Coroutine::create(function () {
// Async logic
});
Coroutine::wait($coroutine);
Custom Middleware
Extend Hyperf\Guzzle\Middleware\MiddlewareInterface:
class CustomLoggingMiddleware implements MiddlewareInterface {
public function __invoke($request, $options, $next) {
\Log::info('Request: ' . $request->getUri());
return $next($request, $options);
}
}
Hyperf Integration
For deeper Hyperf integration, use Hyperf\HttpClient:
use Hyperf\HttpClient\Client;
$client = new Client();
$response = $client->get('https://api.example.com');
Event-Driven Workflows Combine with Laravel events:
Coroutine::create(function () {
$client = app(ClientFactory::class)->create();
$response = $client->get('https://api.example.com/events');
event(new ApiEvent(json_decode($response->getBody(), true)));
});
Retry Strategies Customize retry logic in middleware:
class ExponentialRetryMiddleware implements MiddlewareInterface {
public function __invoke($request, $options, $next) {
$retries = 0;
$maxRetries = 3;
$delay = 100; // ms
while ($retries < $maxRetries) {
try {
return $next($request, $options);
} catch (\Exception $e) {
$retries++;
if ($retries >= $maxRetries) throw $e;
usleep($delay);
$delay *= 2;
}
}
}
}
Swoole Worker Limits
worker_num in swoole.php is sufficient for concurrent coroutines:
'worker_num' => 4, // Adjust based on CPU cores
PHP Settings
max_execution_time and memory_limit for long-running coroutines:
max_execution_time =
How can I help you explore Laravel packages today?