proofdb/app/service/LLM/LLMRetryQueue.php
2026-05-01 23:40:14 +08:00

55 lines
1.8 KiB
PHP

<?php
namespace app\service\LLM;
use Throwable;
class LLMRetryQueue
{
public function run(callable $job, array $config = []): mixed
{
$enabled = (bool) ($config['enabled'] ?? true);
$maxAttempts = max(1, (int) ($config['max_attempts'] ?? 3));
$baseDelayMs = max(0, (int) ($config['base_delay_ms'] ?? 1500));
$maxDelayMs = max($baseDelayMs, (int) ($config['max_delay_ms'] ?? 10000));
$retryStatuses = array_map('intval', $config['retry_statuses'] ?? [429]);
$retryErrorCodes = array_map('strval', $config['retry_error_codes'] ?? ['1302', '1303', '1304', '1305', '1306', '1307', '1308']);
$attempt = 0;
while (true) {
$attempt++;
try {
return $job($attempt);
} catch (Throwable $exception) {
if (!$enabled || $attempt >= $maxAttempts || !$this->shouldRetry($exception, $retryStatuses, $retryErrorCodes)) {
throw $exception;
}
usleep($this->delayMs($attempt, $baseDelayMs, $maxDelayMs) * 1000);
}
}
}
private function shouldRetry(Throwable $exception, array $retryStatuses, array $retryErrorCodes): bool
{
if (!$exception instanceof LLMRequestException) {
return false;
}
if ($exception->statusCode() !== null && in_array($exception->statusCode(), $retryStatuses, true)) {
return true;
}
return $exception->providerCode() !== null && in_array($exception->providerCode(), $retryErrorCodes, true);
}
private function delayMs(int $attempt, int $baseDelayMs, int $maxDelayMs): int
{
$delay = min($maxDelayMs, $baseDelayMs * (2 ** max(0, $attempt - 1)));
$jitter = $delay > 0 ? random_int(0, min(500, $delay)) : 0;
return $delay + $jitter;
}
}