Actualiser api/index.php
CI / PHP Syntax Check (push) Has been cancelled
CI / JavaScript Lint (push) Has been cancelled
CI / Docker Build Test (push) Has been cancelled
CI / Validate Translation Files (push) Has been cancelled
CI / Auto-merge develop → main (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
Security Scan (Trivy) / Trivy — Docker image scan (push) Has been cancelled
Security Scan (Trivy) / Trivy — Filesystem scan (push) Has been cancelled

This commit is contained in:
2026-06-18 11:05:03 +00:00
parent 754daa9989
commit b739cb3a47
+16 -3
View File
@@ -5414,6 +5414,7 @@ function saveSettings(): void {
*/
function callGemini(string $url, array $payload, int $timeout = 60): array {
$maxAttempts = 4;
$maxTotalElapsed = 45; // budget de sécurité pour ne jamais approcher le set_time_limit(120) de PHP
$lastCode = 0;
$lastBody = '';
$promptLen = strlen(json_encode($payload));
@@ -5445,24 +5446,36 @@ function callGemini(string $url, array $payload, int $timeout = 60): array {
if ($body !== false) $lastBody = $body;
// Success or non-retryable error → stop immediately
// Success or non-retryable error → stop immediately
if ($lastCode === 200) break;
if ($lastCode !== 429 && $lastCode !== 503) break;
if ($attempt >= $maxAttempts) break;
// Quota épuisé (RESOURCE_EXHAUSTED) n'est PAS transitoire — retenter le même modèle
// dans cette requête ne servira à rien. On échoue vite plutôt que de risquer que PHP
// tue le script en plein milieu (ce qui remonte comme un 502/504 moche côté client).
$errData = $body ? json_decode($body, true) : null;
if (($errData['error']['status'] ?? '') === 'RESOURCE_EXHAUSTED') {
EverLog::warn('AI quota exhausted, failing fast', ['code' => $lastCode]);
break;
}
// Determine how long to wait -----------------------------------------------
// Priority 1: Retry-After header (set by Google in some 429 responses)
$waitSec = $retryAfterHeader ?? ($attempt * 2); // default: 2 s, 4 s, 6 s
// Priority 2: Google's retryDelay inside the error body (e.g. {"retryDelay":"10s"})
if ($body) {
$errData = json_decode($body, true);
foreach (($errData['error']['details'] ?? []) as $detail) {
if (!empty($detail['retryDelay'])) {
$parsed = intval(preg_replace('/\D/', '', $detail['retryDelay']));
if ($parsed > 0) { $waitSec = min($parsed, 60); break; }
}
}
// Filet de sécurité : jamais laisser le cumul des attentes dépasser le budget
if ((microtime(true) - $t0) + $waitSec >= $maxTotalElapsed) {
EverLog::warn('AI retry budget exhausted, failing fast', ['elapsed' => microtime(true) - $t0]);
break;
}
EverLog::warn('AI rate-limited, retrying', ['attempt' => $attempt, 'wait_s' => $waitSec, 'code' => $lastCode]);