Skip to content

Instantly share code, notes, and snippets.

@ramonsmits
Created June 18, 2025 13:06
Show Gist options
  • Save ramonsmits/ba299b4791cc211ab1103a4e75ce0e3c to your computer and use it in GitHub Desktop.
Save ramonsmits/ba299b4791cc211ab1103a4e75ce0e3c to your computer and use it in GitHub Desktop.
ServiceControl cleanup FailedMessages based on `AddressOfFailingEndpoint`
using Raven.Client.Documents;
using Raven.Client.Documents.Operations;
string FailingEndpointName = args.Length >= 1
? args[0]
: throw new ArgumentException("Missing endpoint name");
int ChunkSize = args.Length >= 2 ? int.Parse(args[1]) : 10000;
using var store = new DocumentStore
{
Urls = ["http://localhost:33334"],
Database = "primary"
};
store.Initialize();
int totalDeleted = 0;
var start = DateTime.UtcNow;
while (true)
{
Console.Write(".");
var countStopwatch = System.Diagnostics.Stopwatch.StartNew();
using var session = store.OpenAsyncSession();
var remaining = await session
.Advanced
.AsyncRawQuery<int>($"""
from FailedMessages
where ProcessingAttempts[].FailureDetails.AddressOfFailingEndpoint = '{FailingEndpointName}'
""")
.WaitForNonStaleResults()
.CountAsync();
countStopwatch.Stop();
if (remaining == 0)
break;
var deleteStopwatch = System.Diagnostics.Stopwatch.StartNew();
Console.Write("•");
// Create and execute a DeleteByQueryOperation
var indexQuery = new Raven.Client.Documents.Queries.IndexQuery
{
Query = $"""
from FailedMessages
where ProcessingAttempts[].FailureDetails.AddressOfFailingEndpoint = '{FailingEndpointName}'
limit {ChunkSize}
"""
};
var deleteOperation = await store.Operations.SendAsync(
new DeleteByQueryOperation(indexQuery)
);
Console.Write("•");
await deleteOperation.WaitForCompletionAsync();
deleteStopwatch.Stop();
Console.Write("•");
int docsDeleted = Math.Min(remaining, ChunkSize);
totalDeleted += docsDeleted;
var elapsed = DateTime.UtcNow - start;
var avgTimePerDoc = elapsed.TotalSeconds / totalDeleted;
var estDocsRemaining = Math.Max(remaining - docsDeleted, 0);
var estTimeRemaining = TimeSpan.FromSeconds(estDocsRemaining * avgTimePerDoc);
Console.Write($" deleted {docsDeleted:N0} (Total: {totalDeleted:N0}) ");
Console.Write($"Count time: {countStopwatch.ElapsedMilliseconds:N0}ms, Delete time: {deleteStopwatch.ElapsedMilliseconds:N0}ms");
if (estDocsRemaining > 0)
Console.WriteLine($", Running: {elapsed} ~{estDocsRemaining:N0}, Remaining ETA: {estTimeRemaining}");
}
Console.WriteLine("All matching documents deleted");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment