Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- `ISupportDryRun` — an opt-in interface exposing `bool IsDryRun { get; set; }` for
ETL stages that support a dry run: the full pipeline is exercised but the external
side effect that mutates a destination or source is skipped. Implemented by the
stage that honours it (not by the base classes). (#259)

### Changed

### Deprecated
Expand Down
42 changes: 42 additions & 0 deletions src/Wolfgang.Etl.Abstractions/ISupportDryRun.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
namespace Wolfgang.Etl.Abstractions;

/// <summary>
/// Implemented by ETL stages that support a <em>dry run</em> — a mode in which the
/// full pipeline is exercised but the external side effect that mutates a destination
/// or source is skipped.
/// </summary>
/// <remarks>
/// A dry run runs the stage exactly as a real run would — enumerating the source,
/// evaluating <c>SkipItemCount</c> and <c>MaximumItemCount</c>, incrementing the
/// progress counters, firing the progress-timer callback and logging as usual — but
/// it does <b>not</b> perform the side effect that mutates external state. This is
/// useful for validating a newly built pipeline (source feed, mapping, batching,
/// throttling) against production data without writing, and for estimating how long
/// a real run would take.
/// <para>
/// The interface is opt-in: a stage advertises it <em>only</em> when it genuinely
/// honours <see cref="IsDryRun"/>. It is therefore the responsibility of the
/// implementer to gate its side effect on <see cref="IsDryRun"/>; the ETL base
/// classes deliberately do not implement this interface because the side effect
/// lives inside the derived stage and the base class has no way to skip it.
/// </para>
/// <para>
/// Dry run applies to any stage with an external side effect — a loader skips its
/// write, and an extractor that mutates its source as it reads (for example
/// committing a message-queue offset, deleting a message on receipt, marking mail
/// read or moving a processed file) skips that acknowledgement. A pure transformer
/// has no external side effect and would not normally implement this interface.
/// </para>
/// </remarks>
public interface ISupportDryRun
{
/// <summary>
/// Gets or sets a value indicating whether the stage runs in dry-run mode.
/// </summary>
/// <value>
/// When <see langword="true"/>, the stage runs the full pipeline but skips the
/// external side effect that mutates the destination or source. Defaults to
/// <see langword="false"/>.
/// </value>
bool IsDryRun { get; set; }
}
3 changes: 3 additions & 0 deletions src/Wolfgang.Etl.Abstractions/PublicAPI.Unshipped.txt
Original file line number Diff line number Diff line change
@@ -1 +1,4 @@
#nullable enable
Wolfgang.Etl.Abstractions.ISupportDryRun
Wolfgang.Etl.Abstractions.ISupportDryRun.IsDryRun.get -> bool
Wolfgang.Etl.Abstractions.ISupportDryRun.IsDryRun.set -> void
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
<PropertyGroup>
<TargetFrameworks>net462;net472;net48;net481;netstandard2.0;net5.0;net6.0;net7.0;net8.0;net9.0;net10.0</TargetFrameworks>
<LangVersion>latest</LangVersion>
<Version>0.14.1</Version>
<Version>0.15.0</Version>
<!-- Pin AssemblyVersion to a fixed binding-stability baseline so consumers
do not need to recompile / add binding redirects on every minor/patch
bump. Bump only on a deliberate breaking API change. FileVersion +
Expand Down
Loading