Webority.Retention 0.2.14

dotnet add package Webority.Retention --version 0.2.14
                    
NuGet\Install-Package Webority.Retention -Version 0.2.14
                    
This command is intended to be used within the Package Manager Console in Visual Studio, as it uses the NuGet module's version of Install-Package.
<PackageReference Include="Webority.Retention" Version="0.2.14" />
                    
For projects that support PackageReference, copy this XML node into the project file to reference the package.
<PackageVersion Include="Webority.Retention" Version="0.2.14" />
                    
Directory.Packages.props
<PackageReference Include="Webority.Retention" />
                    
Project file
For projects that support Central Package Management (CPM), copy this XML node into the solution Directory.Packages.props file to version the package.
paket add Webority.Retention --version 0.2.14
                    
#r "nuget: Webority.Retention, 0.2.14"
                    
#r directive can be used in F# Interactive and Polyglot Notebooks. Copy this into the interactive tool or source code of the script to reference the package.
#:package Webority.Retention@0.2.14
                    
#:package directive can be used in C# file-based apps starting in .NET 10 preview 4. Copy this into a .cs file before any lines of code to reference the package.
#addin nuget:?package=Webority.Retention&version=0.2.14
                    
Install as a Cake Addin
#tool nuget:?package=Webority.Retention&version=0.2.14
                    
Install as a Cake Tool

Webority.Retention

Deletes finished work rows from a product's SQL tables once they pass their retention window: webhook intake, outboxes, idempotency records, side effects, job state. The tables and their rules come from the product's storage register, so the rules live in one place and a push check can verify them.

Using it in a product

1. List the work tables in the register

.webority/data-placement.json names every table with a MAX column or that grows by appending. Entries of class workflow:<days> are trimmed:

{
  "schemaVersion": 1,
  "tables": [
    { "table": "dbo.InboundWebhookDelivery", "class": "workflow:30", "finishedAt": "ProcessedDateTimeUtc", "status": { "column": "Status", "finished": ["Processed", "Ignored"] } },
    { "table": "dbo.NotificationOutboxMessage", "class": "workflow:30", "key": "MessageId", "finishedAt": "SentDateTimeUtc" },
    { "table": "dbo.SalesLead", "class": "record" }
  ]
}
Field Meaning
table schema.table, or the table alone for dbo
class workflow:<days> (1 to 3650) is trimmed; record, bounded-text, document-pointer, analytics and history:<years> are read and left alone
key The bigint or int key column; Id when left out
finishedAt The UTC time the row finished (datetime2, datetime or datetimeoffset); a row where it is null is never deleted
status Optional: column and the finished values. Pending and failed statuses are left out, so those rows are never deleted

A wrong entry, or one that names a missing table or column, fails the whole run before anything is deleted.

Each table needs an unfiltered index whose first column is finishedAt (with status as its second column when the entry has one), because each run reads the oldest due rows first. A table without one fails the run before anything is deleted, and the message names the index to add.

2. Copy the register into the Functions output

<None Include="..\.webority\data-placement.json" Link="data-placement.json" CopyToOutputDirectory="PreserveNewest" />

3. Register and configure

services.AddWeborityRetention();
"Retention": {
  "RegisterPath": "data-placement.json",
  "ConnectionStringName": "WeborityDbConnection",
  "Brake": { "Mode": "DryRun" }
}
Setting Default Meaning
Retention:RegisterPath required The register; a relative path is read from the app's base directory
Retention:ConnectionStringName required Which ConnectionStrings:<name> to trim
Retention:BatchSize 2,000 Rows per delete statement (100 to 4,000, below SQL Server's lock escalation)
Retention:TimeBudget 4 minutes A run stops cleanly when it passes this; the next run carries on
Retention:CommandTimeoutSeconds 60 Per statement
Retention:Brake:Mode DryRun Live deletes; DryRun only logs what would go
Retention:Brake:MaxPerRun 50,000 Most rows one run takes from one table
Retention:Brake:MaxShareOfPopulation 1.0 No share limit: a quiet table can be entirely due

Start in DryRun, read the run log, then set Retention:Brake:Mode to Live in the app settings. No deploy is needed.

4. Call it from a timer

public sealed class RetentionFunction(RetentionRunner runner)
{
    [Function("Retention")]
    public Task RunAsync([TimerTrigger("0 15 * * * *")] TimerInfo timer, CancellationToken cancellationToken)
    {
        return runner.RunAsync(cancellationToken);
    }
}

RunAsync returns a RetentionRunReport with one result per table: Trimmed, NothingDue, DryRun, Refused or OutOfTime. When the brake refuses a table, the other tables are still trimmed, and the run then throws RetentionRunFailedException so it shows as failed.

How a run works

  1. Reads every workflow:<days> entry and checks its table, columns, types and finished-time index against the live schema.
  2. For each table, reads the row count from the partition metadata and the keys of up to MaxPerRun due rows, oldest first.
  3. Checks the plan with the Webority.Jobs destructive-run guard (job Retention).
  4. In Live, deletes in batches. Each delete repeats the due check, so a row that changed after it was planned stays.

Build, test, release

dotnet restore Webority.Retention.slnx
dotnet build Webority.Retention.slnx -c Release --no-restore -v q
dotnet test --solution Webority.Retention.slnx -c Release --no-build

A merge to main publishes to nuget.org; the version of record is VersionPrefix in Directory.Build.props.

Product Compatible and additional computed target framework versions.
.NET net10.0 is compatible.  net10.0-android was computed.  net10.0-browser was computed.  net10.0-ios was computed.  net10.0-maccatalyst was computed.  net10.0-macos was computed.  net10.0-tvos was computed.  net10.0-windows was computed. 
Compatible target framework(s)
Included target framework(s) (in package)
Learn more about Target Frameworks and .NET Standard.

NuGet packages

This package is not used by any NuGet packages.

GitHub repositories

This package is not used by any popular GitHub repositories.

Version Downloads Last Updated
0.2.14 0 11/5/2026
0.2.13 244 11/3/2026
0.2.12 160 11/3/2026
0.2.11 107 11/3/2026
0.2.10 90 11/2/2026
0.2.9 113 11/2/2026
0.2.8 196 11/2/2026
0.2.7 126 11/2/2026
0.2.6 102 11/1/2026
0.2.5 141 11/1/2026
0.2.4 95 11/1/2026
0.2.3 114 11/1/2026
0.2.2 94 11/1/2026
0.2.1 184 10/30/2026
0.2.0 95 10/29/2026
0.1.4 93 10/29/2026
0.1.3 89 10/29/2026
0.1.2 93 10/28/2026
0.1.1 101 10/28/2026
0.1.0 108 10/28/2026