Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Service Client Bundle Laravel Package

deeep/service-client-bundle

View on GitHub
Deep Wiki
Context7

Multi-Host Strategies

🌐 Language: English | Русский

The client supports multiple hosts for high availability and load distribution.

Strategies

Failover

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:

  • Starts with the first host
  • Switches to next on 5xx error or network failure
  • 4xx errors do NOT trigger failover (client error)
  • Returns result immediately on success

Best for: High availability, disaster recovery

Round-Robin

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:

  • Request 1 β†’ Host 1
  • Request 2 β†’ Host 2
  • Request 3 β†’ Host 3
  • Request 4 β†’ Host 1 (wraps around)
  • On failure, moves to next host

Best for: Load balancing, horizontal scaling

Parallel

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 others
  • all β€” Waits for all responses, aggregates results

Best for: Latency optimization, redundant verification

Configuration Options

Health Check

'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.

Per-Host Proxy

'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',
            ],
        ],
    ],
],

Weighted Distribution

'api' => [
    'hosts' => [
        'strategy' => 'round_robin',
        'list' => [
            [
                'url' => 'https://powerful.example.com',
                'weight' => 3,         // Gets 3x more requests
            ],
            [
                'url' => 'https://basic.example.com',
                'weight' => 1,
            ],
        ],
    ],
],

Creating Custom Strategy

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], []);
    }
}

Registering Custom Strategy

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,
            ],
        ],
    ],
],

Error Handling

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(),
        ]);
    }
}

Best Practices

  1. Use failover for critical services β€” Ensures availability
  2. Use round-robin with health checks β€” Prevents sending to dead nodes
  3. Set reasonable timeouts β€” Don't wait forever for slow hosts
  4. Monitor failures β€” Log and set up alerts for host failures
  5. Test failure scenarios β€” Simulate host unavailability on staging
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
jayeshmepani/jpl-moshier-ephemeris-php
elnasnato/laraliveui
labrodev/rest-sdk
sampaui/sampaui
babelqueue/php-sdk
facebook/capi-param-builder-php
babelqueue/symfony
hamzi/corewatch
minionfactory/raw-hydrator
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle