Skip to content

Commit 7dd113a

Browse files
Address PR review feedback on retry semantics
- Clarify MaxRetries XML docs as retries (not total attempts) - Clamp server Retry-After delays to MaxDelayMs - Rethrow original transient exception after retry exhaustion - Remove unnecessary string interpolation marker
1 parent c60be5e commit 7dd113a

2 files changed

Lines changed: 10 additions & 8 deletions

File tree

EssentialCSharp.Chat.Shared/Models/EmbeddingRetryOptions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ public sealed class EmbeddingRetryOptions
1313
public const string SectionPath = "AIOptions:EmbeddingRetry";
1414

1515
/// <summary>
16-
/// Maximum number of retry attempts for transient failures.
17-
/// Default is 5 attempts (initial attempt + 4 retries).
16+
/// Maximum number of retries for transient failures.
17+
/// Default is 5 retries (initial attempt + 5 retries = 6 total attempts).
1818
/// </summary>
1919
[Range(0, 20)]
2020
public int MaxRetries { get; set; } = 5;

EssentialCSharp.Chat.Shared/Services/EmbeddingService.cs

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -160,6 +160,11 @@ private TimeSpan CalculateRetryDelay(int attemptNumber)
160160
return TimeSpan.FromMilliseconds(totalDelayMs);
161161
}
162162

163+
private TimeSpan ClampRetryDelay(TimeSpan delay) =>
164+
delay > TimeSpan.FromMilliseconds(_retryOptions.MaxDelayMs)
165+
? TimeSpan.FromMilliseconds(_retryOptions.MaxDelayMs)
166+
: delay;
167+
163168
/// <summary>
164169
/// Wraps an async operation with retry logic for transient failures.
165170
/// </summary>
@@ -182,7 +187,7 @@ private async Task<T> ExecuteWithRetryAsync<T>(
182187
{
183188
var delay = CalculateRetryDelay(attempt);
184189
var retryAfter = ExtractRetryAfter(ex);
185-
var waitTime = retryAfter ?? delay;
190+
var waitTime = retryAfter.HasValue ? ClampRetryDelay(retryAfter.Value) : delay;
186191
var statusCode = TryGetStatusCode(ex);
187192

188193
if (_logger is not null)
@@ -213,10 +218,7 @@ private async Task<T> ExecuteWithRetryAsync<T>(
213218
TryGetStatusCode(ex));
214219
}
215220

216-
throw new InvalidOperationException(
217-
$"Operation {operationName} failed after {_retryOptions.MaxRetries + 1} total attempts " +
218-
$"({_retryOptions.MaxRetries} retries). Last error: {ex.Message}",
219-
ex);
221+
throw;
220222
}
221223
catch (Exception ex)
222224
{
@@ -236,7 +238,7 @@ public async Task<ReadOnlyMemory<float>> GenerateEmbeddingAsync(string text, Can
236238
{
237239
var embedding = await ExecuteWithRetryAsync(
238240
async ct => await embeddingGenerator.GenerateAsync(text, cancellationToken: ct),
239-
$"GenerateEmbedding",
241+
"GenerateEmbedding",
240242
cancellationToken);
241243
return embedding.Vector;
242244
}

0 commit comments

Comments
 (0)