Round #245

07 May 2026, 20:47· csharp· meta/llama-3.3-70b-instruct· r13-clean-hints
Complexity
band 0
ZP / UO / OBS
4 / 2 / 1
Journey weight
511
Lightshift ΔL
+0.13

Prompt

Write a worker that retries failed outbox messages with exponential backoff

Zero-point index (what the engine surfaced)

ZPI-ZPI-0013 | 2026-05-07T20:47:20Z Write a worker that retries failed outbox messages with exponential backoff ZERO POINT — 4 entries (structural invariants) ● hsl(296.42, 100%, 27%) ResiliencePipeline [contract] ● hsl(211.57, 100%, 27%) ResiliencePipelineBuilder [contract] ● hsl(136.10, 100%, 21%) DbContext [contract] ● hsl(61.72, 100%, 21%) BackgroundService [contract] UNOBSERVED — 2 entries (implied truths) ○ hsl(27.69, 100%, 50%) async [feature] ○ hsl(3.75, 100%, 21%) CancellationToken [feature] OBSERVED — 1 entries (explicit in request) ◉ hsl(98.46, 100%, 21%) with [feature] COMPLEXITY │ 7 entries │ spread: 95° │ band: LOW

Baseline response (no ZPI)

**Exponential Backoff Worker for Retrying Failed Outbox Messages** =========================================================== Below is an example implementation of a worker in C# that retries failed outbox messages with exponential backoff. ### Prerequisites * .NET 6.0 or later * `Microsoft.Extensions.Hosting` package for hosting the worker * `Microsoft.Extensions.Logging` package for logging * `System.Threading` package for threading and timing ### Implementation ```csharp using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using System; using System.Threading; using System.Threading.Tasks; public class OutboxMessage { public string Id { get; set; } public string Message { get; set; } } public interface IOutboxRepository { OutboxMessage GetFailedMessage(); void UpdateMessageStatus(string id, string status); } public class OutboxWorker : BackgroundService { private readonly IOutboxRepository _outboxRepository; private readonly ILogger<OutboxWorker> _logger; private readonly int _maxAttempts = 5; private readonly int _initialDelay = 1000; // 1 second private readonly int _maxDelay = 30000; // 30 seconds public OutboxWorker(IOutboxRepository outboxRepository, ILogger<OutboxWorker> logger) { _outboxRepository = outboxRepository; _logger = logger; } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { var failedMessage = _outboxRepository.GetFailedMessage(); if (failedMessage != null) { await RetrySendMessage(failedMessage, stoppingToken); } else { await Task.Delay(1000, stoppingToken); // wait 1 second before checking again } } } private async Task RetrySendMessage(OutboxMessage message, CancellationToken stoppingToken) { int attempt = 0; int delay = _initialDelay; while (attempt < _maxAttempts && !stoppingToken.IsCancellationRequested) { try { // Simulate sending the message await SendMessage(message); _outboxRepository.UpdateMessageStatus(message.Id, "Sent"); _logger.LogInformation($"Message {message.Id} sent successfully"); return; } catch (Exception ex) { attempt++; _logger.LogWarning($"Failed to send message {message.Id} (attempt {attempt}/{_maxAttempts}): {ex.Message}"); await Task.Delay(delay, stoppingToken); delay = Math.Min(delay * 2, _maxDelay); // exponential backoff } } _logger.LogError($"Failed to send message {message.Id} after {_maxAttempts} attempts"); _outboxRepository.UpdateMessageStatus(message.Id, "Failed"); } private async Task SendMessage(OutboxMessage message) { // Simulate sending the message (replace with actual implementation) await Task.Delay(100); // throw new Exception("Simulated error"); // uncomment to test retry logic } } ``` ### Explanation 1. The `OutboxWorker` class inherits from `BackgroundService` and overrides the `ExecuteAsync` method to run the worker. 2. The worker checks for failed outbox messages every second and retries sending them with exponential backoff. 3. The `RetrySendMessage` method attempts to send the message up to a maximum number of attempts (`_maxAttempts`) with increasing delays between attempts. 4. If all attempts fail, the message is marked as failed and logged. ### Example Use Case To use this worker, create an instance of the `OutboxWorker` class and start it using the `Host` class: ```csharp using Microsoft.Extensions.Hosting; class Program { static async Task Main(string[] args) { var host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { services.AddSingleton<IOutboxRepository, OutboxRepository>(); services.AddHostedService<OutboxWorker>(); }) .Build(); await host.RunAsync(); } } ``` Replace the `OutboxRepository` class with your actual implementation of storing and retrieving outbox messages.

Enhanced response (with ZPI)

```csharp using Microsoft.Extensions.DependencyInjection; using Microsoft.Extensions.Hosting; using Microsoft.Extensions.Logging; using Polly; using System; using System.Threading; using System.Threading.Tasks; public class OutboxMessage { public int Id { get; set; } public string Message { get; set; } } public interface IOutboxMessageRepository { OutboxMessage GetNextFailedMessage(); void MarkMessageAsSent(int messageId); void MarkMessageAsFailed(int messageId); } public class OutboxMessageRepository : IOutboxMessageRepository { private readonly DbContext _dbContext; public OutboxMessageRepository(DbContext dbContext) { _dbContext = dbContext; } public OutboxMessage GetNextFailedMessage() { // Implement database logic to retrieve the next failed message throw new NotImplementedException(); } public void MarkMessageAsSent(int messageId) { // Implement database logic to mark the message as sent throw new NotImplementedException(); } public void MarkMessageAsFailed(int messageId) { // Implement database logic to mark the message as failed throw new NotImplementedException(); } } public class OutboxMessageWorker : BackgroundService { private readonly IOutboxMessageRepository _repository; private readonly ILogger<OutboxMessageWorker> _logger; private readonly Policy _retryPolicy; public OutboxMessageWorker(IOutboxMessageRepository repository, ILogger<OutboxMessageWorker> logger) { _repository = repository; _logger = logger; _retryPolicy = Policy.Handle<Exception>() .WaitAndRetryAsync( retryCount: 5, retryAttempt => TimeSpan.FromSeconds(Math.Pow(2, retryAttempt)), (exception, timeSpan, retryCount, context) => { _logger.LogWarning(exception, "Failed to send outbox message. Retrying in {TimeSpan} seconds.", timeSpan); }); } protected override async Task ExecuteAsync(CancellationToken stoppingToken) { while (!stoppingToken.IsCancellationRequested) { var message = _repository.GetNextFailedMessage(); if (message != null) { try { await _retryPolicy.ExecuteAsync(async () => { // Implement logic to send the message await SendOutboxMessage(message); _repository.MarkMessageAsSent(message.Id); }); } catch (Exception ex) { _repository.MarkMessageAsFailed(message.Id); _logger.LogError(ex, "Failed to send outbox message."); } } else { await Task.Delay(TimeSpan.FromSeconds(10), stoppingToken); } } } private async Task SendOutboxMessage(OutboxMessage message) { // Implement logic to send the message throw new NotImplementedException(); } } public class Program { public static void Main(string[] args) { var host = Host.CreateDefaultBuilder(args) .ConfigureServices(services => { services.AddDbContext<DbContext>(); services.AddTransient<IOutboxMessageRepository, OutboxMessageRepository>(); services.AddHostedService<OutboxMessageWorker>(); }) .Build(); host.Run(); } } ``` This implementation uses the `BackgroundService` class to create a worker that runs in the background and retries failed outbox messages with exponential backoff. The `OutboxMessageRepository` class is used to interact with the database and retrieve the next failed message. The `OutboxMessageWorker` class uses Polly to implement the retry policy with exponential backoff. The `OutboxMessageWorker` class is registered as a hosted service in the `Program` class, and the `IOutboxMessageRepository` interface is registered as a transient service. The `DbContext` is also registered as a service. The `SendOutboxMessage` method is not implemented in this example, as it would depend on the specific requirements of your application. You would need to replace this method with your own implementation to send the outbox message. The retry policy is configured to retry up to 5 times with exponential backoff, waiting 2, 4, 8, 16, and 32 seconds between retries. If all retries fail, the message is marked as failed in the database. If the message is sent successfully, it is marked as sent in the database.

Grader chain

Each grader reads the same baseline + enhanced pair and casts an independent verdict. Disagreement is the framework's own signal — not noise to be averaged away.

V1claude-haiku-4-5-20251001
Better
V4qwen2.5-coder-7b-instruct
Better

Comments

Our grader said what it said. What do you say? Comment as a guest below.

No comments yet. Be the first to say what you make of this round.

← back to all rounds