Injectable internal time source for deterministic Report timing (#338) - #339
Merged
Conversation
…#338) Add an internal ITimeSource seam (StartedAt/Elapsed and the throughput metrics derived from them) so timing can be driven from a fake clock in tests, unblocking ETL-Test-Kit#262. - Internal ITimeSource + SystemTimeSource (default = DateTimeOffset.UtcNow + Stopwatch, net462-safe; NOT TimeProvider which is net8+). - ExtractorBase/LoaderBase/TransformerBase read StartedAt/Elapsed through an internal TimeSource field (mirrors the internal TimerCoreFactory seam); EtlRunState reads elapsed through an injected ITimeSource (internal ctor). Default behaviour identical (real clock). - InternalsVisibleTo("Wolfgang.Etl.TestKit") so Test-Kit doubles can inject a fake. NO public API change (all internal) — pack + Package Validation green vs 0.18.1. 419 tests (6 new ClockSeamTests); Stryker 100.00% (0 survivors); all 11 TFMs clean. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
BenchmarkDotNet
Details
| Benchmark suite | Current: 80a987b | Previous: 3a14ba9 | Ratio |
|---|---|---|---|
Wolfgang.Etl.Abstractions.Benchmarks.ExtractorBenchmarks.Extract_NoProgress(RecordCount: 1000) |
33666.0446879069 ns (± 212.76288582877567) |
31930.534067789715 ns (± 658.2371578009119) |
1.05 |
Wolfgang.Etl.Abstractions.Benchmarks.ExtractorBenchmarks.Extract_WithProgress(RecordCount: 1000) |
35506.2731628418 ns (± 107.57179946508552) |
34010.91799926758 ns (± 129.0833785595842) |
1.04 |
Wolfgang.Etl.Abstractions.Benchmarks.ExtractorBenchmarks.Extract_NoProgress(RecordCount: 100000) |
3277068.0911458335 ns (± 8584.100422777798) |
3106942.7135416665 ns (± 3078.2601995964997) |
1.05 |
Wolfgang.Etl.Abstractions.Benchmarks.ExtractorBenchmarks.Extract_WithProgress(RecordCount: 100000) |
3437550.6783854165 ns (± 1508.719338267254) |
3369861.2369791665 ns (± 3214.804757548345) |
1.02 |
Wolfgang.Etl.Abstractions.Benchmarks.PipelineBenchmarks.FluentPipeline(RecordCount: 1000) |
32726.99262491862 ns (± 87.5185674075267) |
29861.78623453776 ns (± 94.08997512637652) |
1.10 |
Wolfgang.Etl.Abstractions.Benchmarks.PipelineBenchmarks.ManualComposition(RecordCount: 1000) |
32577.454701741535 ns (± 135.16839236479976) |
29908.161814371746 ns (± 70.64600581703343) |
1.09 |
Wolfgang.Etl.Abstractions.Benchmarks.PipelineBenchmarks.BaseClassComposition(RecordCount: 1000) |
70143.9028930664 ns (± 259.1320549837876) |
68483.69946289062 ns (± 285.6650714675182) |
1.02 |
Wolfgang.Etl.Abstractions.Benchmarks.PipelineBenchmarks.FluentPipeline(RecordCount: 100000) |
3202521.47265625 ns (± 2726.351303727282) |
2854886.4140625 ns (± 1462.1467840974312) |
1.12 |
Wolfgang.Etl.Abstractions.Benchmarks.PipelineBenchmarks.ManualComposition(RecordCount: 100000) |
3205984.3424479165 ns (± 755.3263901337803) |
2870112.7330729165 ns (± 326.26898943322766) |
1.12 |
Wolfgang.Etl.Abstractions.Benchmarks.PipelineBenchmarks.BaseClassComposition(RecordCount: 100000) |
6930356.3515625 ns (± 7031.847933564747) |
6728828.515625 ns (± 4243.902731655375) |
1.03 |
This comment was automatically generated by workflow using github-action-benchmark.
This was referenced Jul 29, 2026
This was referenced Aug 5, 2026
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Closes #338. Targets
vNextso it ships in 0.19.0.Summary
Adds an internal injectable time source so the base classes'
Reporttiming metrics (StartedAt,Elapsed, and the throughput values derived from them) can be driven from a fake clock in tests — unblocking ETL-Test-Kit #262.internal interface ITimeSource(UtcNow,GetTimestamp(),TimestampFrequency) +SystemTimeSourcedefault (realDateTimeOffset.UtcNow+Stopwatch). NotTimeProvider— that's net8+-only and we target net462/netstandard2.0.ExtractorBase/LoaderBase/TransformerBasereadStartedAt/Elapsedthrough aninternal ITimeSource? TimeSourcefield (same shape as the existing internalTimerCoreFactoryseam).EtlRunStatereads its elapsed through an injectedITimeSource(internal ctor). Default behaviour is byte-for-byte identical (real clock).InternalsVisibleTo("Wolfgang.Etl.TestKit")so Test-Kit's doubles can set the fake — the visibility approach chosen for this change.No public API change
Everything is
internal. Pack + Package Validation stay green against the 0.18.1 baseline, soPublicAPI.Shipped/Unshippedare untouched and the 0.19.0 release prep (PR #337) remains valid.Verification
ClockSeamTests: fake-drivenStartedAt/Elapsedon all 3 bases, before-first-item null/zero, real-clock default path,EtlRunStateelapsed).Merge path
Base is
vNext. Once green, merging this intovNextfolds it into the 0.19.0 release PR (#337) automatically. No public-API/PublicAPI churn, so it does not disturb the prep.