π Language: English | Π ΡΡΡΠΊΠΈΠΉ
The client supports multiple hosts for high availability and load distribution.
Tries hosts in order, switches to next on error.
<?php
// config/packages/deeep_service_client.php
declare(strict_types=1);
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
return App::config([
'deeep_service_client' => [
'services' => [
'api' => [
'hosts' => [
'strategy' => 'failover',
'list' => [
['url' => 'https://primary.example.com'],
['url' => 'https://secondary.example.com'],
['url' => 'https://tertiary.example.com'],
],
],
],
],
],
]);
Behavior:
Best for: High availability, disaster recovery
Distributes requests evenly across hosts.
'api' => [
'hosts' => [
'strategy' => 'round_robin',
'health_check' => [
'enabled' => true,
'interval' => 30,
'path' => '/health',
],
'list' => [
['url' => 'https://node1.example.com'],
['url' => 'https://node2.example.com'],
['url' => 'https://node3.example.com'],
],
],
],
Behavior:
Best for: Load balancing, horizontal scaling
Sends request to all hosts simultaneously.
'api' => [
'hosts' => [
'strategy' => 'parallel',
'mode' => 'first', // first or all
'timeout' => 5.0,
'list' => [
['url' => 'https://fast.example.com'],
['url' => 'https://slow.example.com'],
],
],
],
Modes:
first β Returns first successful response, cancels othersall β Waits for all responses, aggregates resultsBest for: Latency optimization, redundant verification
'api' => [
'hosts' => [
'strategy' => 'round_robin',
'health_check' => [
'enabled' => true,
'interval' => 30, // Check every 30 seconds
'path' => '/health', // Health endpoint path
'timeout' => 5, // Check timeout
],
'list' => [
['url' => 'https://node1.example.com'],
['url' => 'https://node2.example.com'],
],
],
],
Unhealthy hosts are excluded from rotation until recovered.
'api' => [
'hosts' => [
'strategy' => 'failover',
'list' => [
[
'url' => 'https://api.example.com',
'proxy' => 'http://proxy1.local:8080',
],
[
'url' => 'https://api.example.com',
'proxy' => 'http://proxy2.local:8080',
],
],
],
],
'api' => [
'hosts' => [
'strategy' => 'round_robin',
'list' => [
[
'url' => 'https://powerful.example.com',
'weight' => 3, // Gets 3x more requests
],
[
'url' => 'https://basic.example.com',
'weight' => 1,
],
],
],
],
use Deeep\ServiceClient\Config\HostConfig;
use Deeep\ServiceClient\Contract\HostResultInterface;
use Deeep\ServiceClient\Contract\HostStrategyInterface;
use Deeep\ServiceClient\Contract\RequestInterface;
use Deeep\ServiceClient\Host\HostResult;
final class WeightedRandomStrategy implements HostStrategyInterface
{
public function getName(): string
{
return 'weighted_random';
}
public function execute(
RequestInterface $request,
array $hosts,
callable $sender,
): HostResultInterface {
$totalWeight = array_sum(array_map(
static fn(HostConfig $h) => $h->weight,
$hosts,
));
$random = random_int(1, $totalWeight);
$current = 0;
foreach ($hosts as $host) {
$current += $host->weight;
if ($random <= $current) {
$response = $sender($request, $host);
return new HostResult($response, $host, []);
}
}
// Fallback to first host
$response = $sender($request, $hosts[0]);
return new HostResult($response, $hosts[0], []);
}
}
The strategy will be automatically registered via HostStrategyInterface. Or manually via tag:
<?php
// config/services.php
declare(strict_types=1);
namespace Symfony\Component\DependencyInjection\Loader\Configurator;
use App\Host\WeightedRandomStrategy;
return static function (ContainerConfigurator $container): void {
$services = $container->services();
$services->set(WeightedRandomStrategy::class)
->tag('deeep_service_client.host_strategy');
};
Then use in configuration:
'api' => [
'hosts' => [
'strategy' => 'weighted_random',
'list' => [
[
'url' => 'https://primary.example.com',
'weight' => 5,
],
[
'url' => 'https://secondary.example.com',
'weight' => 1,
],
],
],
],
When all hosts are unavailable:
use Deeep\ServiceClient\Exception\AllHostsFailedException;
try {
$response = $client->send($request);
} catch (AllHostsFailedException $e) {
$failures = $e->getFailures();
// [
// ['host' => HostConfig, 'response' => ResponseInterface],
// ['host' => HostConfig, 'error' => Throwable],
// ]
foreach ($failures as $failure) {
$logger->error('Host unavailable', [
'host' => $failure['host']->getBaseUrl(),
'error' => $failure['error'] ?? $failure['response']->getStatusCode(),
]);
}
}
How can I help you explore Laravel packages today?