Avoid retrying exhausted OpenAI quota
This commit is contained in:
parent
0f83f739c5
commit
24bafca765
@ -39,6 +39,7 @@ var tests = new (string Name, Action Test)[]
|
||||
("Illustration starter generation plan skips successful items", IllustrationStarterGenerationPlanSkipsSuccessfulItems),
|
||||
("Story Intelligence prototype uses starter illustration codes", StoryIntelligencePrototypeUsesStarterIllustrationCodes),
|
||||
("Story Intelligence simulation mode remains available", StoryIntelligenceSimulationModeRemainsAvailable),
|
||||
("Story Intelligence does not retry exhausted billing quota", StoryIntelligenceDoesNotRetryExhaustedBillingQuota),
|
||||
("Story Intelligence visualisation contract omits raw manuscript text", StoryIntelligenceVisualisationContractOmitsRawManuscriptText),
|
||||
("Illustration bulk retry result reports counts", IllustrationBulkRetryResultReportsCounts),
|
||||
("Illustration bulk retry skips blocking duplicate stable codes", IllustrationBulkRetrySkipsBlockingDuplicateStableCodes),
|
||||
@ -698,6 +699,14 @@ static void StoryIntelligenceSimulationModeRemainsAvailable()
|
||||
Assert(prototype.Scenes.Any(scene => scene.PovCharacterId == "rosie"), "Simulation should still exercise POV transitions.");
|
||||
}
|
||||
|
||||
static void StoryIntelligenceDoesNotRetryExhaustedBillingQuota()
|
||||
{
|
||||
var client = File.ReadAllText(Path.Combine(AppContext.BaseDirectory, "../../../../PlotLine/Services/StoryIntelligenceOpenAIInfrastructure.cs"));
|
||||
|
||||
Assert(client.Contains("IsInsufficientQuota(responseText)", StringComparison.Ordinal), "OpenAI insufficient_quota responses must be detected before retrying.");
|
||||
Assert(client.Contains("request was not retried", StringComparison.Ordinal), "OpenAI insufficient_quota responses should fail clearly without retry churn.");
|
||||
}
|
||||
|
||||
static void StoryIntelligenceVisualisationContractOmitsRawManuscriptText()
|
||||
{
|
||||
var model = new StoryIntelligenceExperiencePrototypeViewModel
|
||||
|
||||
@ -279,6 +279,11 @@ public sealed class StoryIntelligenceClient(
|
||||
return (responseText, retryCount);
|
||||
}
|
||||
|
||||
if (IsInsufficientQuota(responseText))
|
||||
{
|
||||
throw new InvalidOperationException($"OpenAI billing quota exhausted; request was not retried: {TrimForLog(responseText)}");
|
||||
}
|
||||
|
||||
if (!ShouldRetry(response.StatusCode) || attempt == maxAttempts)
|
||||
{
|
||||
throw new InvalidOperationException($"OpenAI request failed with {(int)response.StatusCode} {response.StatusCode}: {TrimForLog(responseText)}");
|
||||
@ -318,6 +323,10 @@ public sealed class StoryIntelligenceClient(
|
||||
or HttpStatusCode.ServiceUnavailable
|
||||
or HttpStatusCode.GatewayTimeout;
|
||||
|
||||
internal static bool IsInsufficientQuota(string responseText)
|
||||
=> responseText.Contains("\"insufficient_quota\"", StringComparison.OrdinalIgnoreCase)
|
||||
|| responseText.Contains("exceeded your current quota", StringComparison.OrdinalIgnoreCase);
|
||||
|
||||
private static Task DelayForRetryAsync(int attempt, CancellationToken cancellationToken)
|
||||
=> Task.Delay(TimeSpan.FromSeconds(Math.Pow(2, attempt - 1)), cancellationToken);
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user