diff --git a/app/Services/SmsBilling/SuperAdminSmsClient.php b/app/Services/SmsBilling/SuperAdminSmsClient.php index ed3c792..62f3dfd 100644 --- a/app/Services/SmsBilling/SuperAdminSmsClient.php +++ b/app/Services/SmsBilling/SuperAdminSmsClient.php @@ -3,6 +3,7 @@ namespace App\Services\SmsBilling; use App\Http\Controllers\Controller; +use Illuminate\Http\Client\Pool; use Illuminate\Http\Client\Response; use Illuminate\Support\Facades\Cache; use Illuminate\Support\Facades\Http; @@ -201,6 +202,27 @@ class SuperAdminSmsClient $method = strtoupper($method); $lastError = null; + if ($method === 'GET' && count($bases) > 1) { + $parallel = $this->requestJsonParallel( + $bases, + $canonicalPath, + $relativeUrl, + $query, + $timeout, + $label + ); + if ($parallel !== null) { + return $parallel; + } + + $this->forgetSuccessfulBase(); + Log::warning("SuperAdmin SMS {$label} unavailable on all bases (parallel GET)", [ + 'bases' => $bases, + ]); + + return null; + } + foreach ($bases as $index => $base) { try { $pending = Http::withHeaders($this->authHeaders($method, $canonicalPath)) @@ -256,6 +278,8 @@ class SuperAdminSmsClient } } + $this->forgetSuccessfulBase(); + Log::warning("SuperAdmin SMS {$label} unavailable on all bases", [ 'bases' => $bases, 'last_error' => $lastError, @@ -264,6 +288,88 @@ class SuperAdminSmsClient return null; } + /** + * Fan-out GET to all SuperAdmin hosts in parallel (max wait = one timeout, not NĂ—timeout). + * + * @param list $bases + * @param array $query + * @return array|null + */ + private function requestJsonParallel( + array $bases, + string $canonicalPath, + string $relativeUrl, + array $query, + int $timeout, + string $label + ): ?array { + $headers = $this->authHeaders('GET', $canonicalPath); + $options = Controller::httpClientOptions([], (float) $timeout); + + try { + /** @var array $responses */ + $responses = Http::pool(function (Pool $pool) use ($bases, $headers, $relativeUrl, $query, $timeout, $options) { + foreach ($bases as $index => $base) { + $pool->as((string) $index) + ->withHeaders($headers) + ->acceptJson() + ->connectTimeout(2) + ->timeout($timeout) + ->withOptions($options) + ->get($this->urlForBase($base, $relativeUrl), $query); + } + }); + } catch (\Throwable $e) { + Log::warning("SuperAdmin SMS {$label} parallel pool failed", [ + 'error' => $e->getMessage(), + ]); + + return null; + } + + foreach ($bases as $index => $base) { + $key = (string) $index; + if (! array_key_exists($key, $responses)) { + continue; + } + + $response = $responses[$key]; + if ($response instanceof \Throwable) { + Log::warning("SuperAdmin SMS {$label} parallel exception", [ + 'base' => $base, + 'error' => $response->getMessage(), + ]); + + continue; + } + + if (! $response->successful()) { + Log::warning("SuperAdmin SMS {$label} parallel failed", [ + 'base' => $base, + 'status' => $response->status(), + 'body' => $response->body(), + ]); + + continue; + } + + $data = $response->json(); + if (! is_array($data)) { + Log::warning("SuperAdmin SMS {$label} parallel invalid JSON", [ + 'base' => $base, + ]); + + continue; + } + + $this->rememberSuccessfulBase($base); + + return $data; + } + + return null; + } + /** * @return list */ @@ -340,6 +446,17 @@ class SuperAdminSmsClient } } + private function forgetSuccessfulBase(): void + { + try { + Cache::forget(self::SUCCESS_BASE_CACHE_KEY); + } catch (\Throwable $e) { + Log::debug('SuperAdmin SMS sticky base cache forget failed', [ + 'error' => $e->getMessage(), + ]); + } + } + private function readSuccessfulBase(): ?string { try {