Skip to content
Tracon

IRetentionStore

Namespace Tracon · Assembly Tracon.Abstractions.dll

The data plane that counts, batch-deletes, and reads-for-archive over the actual retention data.

public interface IRetentionStore

The target name parameter always comes from the RetentionTargets allowlist; implementations must throw ArgumentException for an unknown target.

Which column counts as “age” and which extra condition (for example, only completed jobs) applies is fixed for EACH target and stays embedded inside the implementation; the caller knows only the target name and the cutoff date.

Tenant scoping is mandatory. A retention policy is defined per tenant; if tenantId is not given, the operation touches every tenant’s rows. Only the installation-wide ('*') policy should pass null.

The default (in-memory) setup registers NullRetentionStore, which always returns empty/zero: retention is meaningful only when a SQL provider is enabled.

DI lifetime — singleton. Registered as a singleton with TryAdd; a consumer’s own registration wins.

ArchiveBatchAsync(string, string?, DateTimeOffset, int, Func<IReadOnlyList<ArchiveRow>, CancellationToken, ValueTask>, CancellationToken)

Section titled “ ArchiveBatchAsync(string, string?, DateTimeOffset, int, Func<IReadOnlyList<ArchiveRow>, CancellationToken, ValueTask>, CancellationToken)”

Reads one batch of rows older than the cutoff date, hands it to archiveAsync, and then deletes exactly the rows of that batch.

ValueTask<int> ArchiveBatchAsync(string target, string? tenantId, DateTimeOffset cutoff, int batchSize, Func<IReadOnlyList<ArchiveRow>, CancellationToken, ValueTask> archiveAsync, CancellationToken cancellationToken = default)

target string

The target name.

tenantId string?

Only this tenant’s rows; if null, runs installation-wide (the '*' policy).

cutoff DateTimeOffset

The cutoff date (UTC).

batchSize int

The maximum number of rows to archive and delete.

archiveAsync Func<IReadOnlyList<ArchiveRow>, CancellationToken, ValueTask>

Writes the batch to the archive. It is not called when no row matches. When it throws, no row is deleted and the exception propagates.

cancellationToken CancellationToken

The cancellation token.

ValueTask<int>

The number of rows deleted. It is never more than the number of rows handed to archiveAsync; zero when no row matched.

This is the archive mode of a retention run: a row that was not handed to archiveAsync is never deleted. A row that stops matching between the read and the delete is kept. It is archived again when it matches on a later run, so an IArchiveSink can receive the same row more than once.

For RetentionTargets.Attachments with an IAttachmentStorage registered, the external content of each archived row is deleted BEFORE the row, the same as in IRetentionStore.DeleteBatchAsync; a row whose content delete fails is kept.

The default implementation calls IRetentionStore.ReadForArchiveAsync and then IRetentionStore.DeleteBatchAsync with the number of rows read. It is not EXACT: the two calls can select different rows, and a row that was never archived can be deleted. It exists only so a store written before this member keeps compiling. The SQL stores override it; the shipped RetentionStoreContract checks the rule above.

CountOlderThanAsync(string, string?, DateTimeOffset, CancellationToken)

Section titled “ CountOlderThanAsync(string, string?, DateTimeOffset, CancellationToken)”

Returns the number of rows in the target currently older than the cutoff date.

ValueTask<long> CountOlderThanAsync(string target, string? tenantId, DateTimeOffset cutoff, CancellationToken cancellationToken = default)

target string

The target name.

tenantId string?

Only this tenant’s rows; if null, runs installation-wide (the '*' policy).

cutoff DateTimeOffset

The cutoff date (UTC). Rows older than this match.

cancellationToken CancellationToken

The cancellation token.

ValueTask<long>

The number of matching rows.

DeleteBatchAsync(string, string?, DateTimeOffset, int, CancellationToken)

Section titled “ DeleteBatchAsync(string, string?, DateTimeOffset, int, CancellationToken)”

Deletes a batch of rows older than the cutoff date. This is not a single bulk DELETE; it runs batch by batch, depending on the provider.

ValueTask<int> DeleteBatchAsync(string target, string? tenantId, DateTimeOffset cutoff, int batchSize, CancellationToken cancellationToken = default)

target string

The target name.

tenantId string?

Only this tenant’s rows; if null, runs installation-wide (the '*' policy).

cutoff DateTimeOffset

The cutoff date (UTC).

batchSize int

The maximum number of rows to delete.

cancellationToken CancellationToken

The cancellation token.

ValueTask<int>

The number of rows deleted. Zero means no matching row could be deleted: usually none remain, but see the remarks.

For RetentionTargets.Attachments with an IAttachmentStorage registered, each row’s external content is deleted BEFORE the row. A row whose content delete fails is kept and still matches, so a batch can return fewer rows than batchSize while matching rows remain. The next run tries the kept row again.

The batch has no order, so this method is for a run that does not archive. A run that archives uses IRetentionStore.ArchiveBatchAsync.

FindRowLimitCutoffAsync(string, string?, long, CancellationToken)

Section titled “ FindRowLimitCutoffAsync(string, string?, long, CancellationToken)”

Counting from newest, returns the ordering column’s value at row maxRows as the cutoff date.

ValueTask<DateTimeOffset?> FindRowLimitCutoffAsync(string target, string? tenantId, long maxRows, CancellationToken cancellationToken = default)

target string

The target name.

tenantId string?

Only this tenant’s rows; if null, runs installation-wide (the '*' policy).

maxRows long

The maximum number of rows to keep (at least 1).

cancellationToken CancellationToken

The cancellation token.

ValueTask<DateTimeOffset?>

The cutoff date; null if the target holds FEWER than maxRows rows (the volume limit is not exceeded).

The returned value can be passed directly into this interface’s other three methods (the @cutoff parameter): volume-based trimming uses the SAME batch mechanism as age-based deletion.

ReadForArchiveAsync(string, string?, DateTimeOffset, int, CancellationToken)

Section titled “ ReadForArchiveAsync(string, string?, DateTimeOffset, int, CancellationToken)”

Reads a batch of rows older than the cutoff date (does not delete).

ValueTask<IReadOnlyList<ArchiveRow>> ReadForArchiveAsync(string target, string? tenantId, DateTimeOffset cutoff, int batchSize, CancellationToken cancellationToken = default)

target string

The target name.

tenantId string?

Only this tenant’s rows; if null, runs installation-wide (the '*' policy).

cutoff DateTimeOffset

The cutoff date (UTC).

batchSize int

The maximum number of rows to read.

cancellationToken CancellationToken

The cancellation token.

ValueTask<IReadOnlyList<ArchiveRow>>

The rows read; an empty list once no matching rows remain.

The rows come in the target’s time order. IRetentionStore.DeleteBatchAsync deletes in no order, so the two calls can select different rows: archive and delete a batch with IRetentionStore.ArchiveBatchAsync instead.