Skip to content

Commit 0743fda

Browse files
authored
track total egress bytes on stow (#3337)
track total egress bytes on stow
1 parent 4f2bd5d commit 0743fda

File tree

5 files changed

+84
-1
lines changed

5 files changed

+84
-1
lines changed

src/Microsoft.Health.Dicom.Api.UnitTests/Features/Context/DefaultDicomRequestContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,9 @@ public class DefaultDicomRequestContext : IDicomRequestContext
5151
public IDictionary<string, StringValues> ResponseHeaders { get; set; }
5252

5353
public int Version { get; set; }
54+
55+
/// <summary>
56+
/// Egress bytes from Dicom server to other resources
57+
/// </summary>
58+
public long TotalDicomEgressToStorageBytes { get; set; }
5459
}

src/Microsoft.Health.Dicom.Core.UnitTests/Features/Store/DicomStoreServiceTests.cs

Lines changed: 68 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -155,12 +155,15 @@ public async Task GivenAValidDicomInstanceEntry_WhenProcessed_ThenSuccessfulEntr
155155
IDicomInstanceEntry dicomInstanceEntry = Substitute.For<IDicomInstanceEntry>();
156156

157157
dicomInstanceEntry.GetDicomDatasetAsync(DefaultCancellationToken).Returns(_dicomDataset1);
158+
long bytesStored = 100L;
159+
_storeOrchestrator.StoreDicomInstanceEntryAsync(dicomInstanceEntry, DefaultCancellationToken).Returns(bytesStored);
158160

159161
await ExecuteAndValidateAsync(dicomInstanceEntry);
160162

161163
_storeResponseBuilder.Received(1).AddSuccess(_dicomDataset1, DefaultStoreValidationResult, _dicomRequestContext.DataPartition);
162164
_storeResponseBuilder.DidNotReceiveWithAnyArgs().AddFailure(default);
163165
Assert.Equal(1, _dicomRequestContextAccessor.RequestContext.PartCount);
166+
Assert.Equal(bytesStored, _dicomRequestContextAccessor.RequestContext.TotalDicomEgressToStorageBytes);
164167
}
165168

166169
[Fact]
@@ -174,6 +177,8 @@ public async Task GiveAnInvalidDicomDataset_WhenProcessed_ThenFailedEntryShouldB
174177

175178
_storeResponseBuilder.DidNotReceiveWithAnyArgs().AddSuccess(default, DefaultStoreValidationResult, Partition.Default);
176179
_storeResponseBuilder.Received(1).AddFailure(null, TestConstants.ProcessingFailureReasonCode);
180+
Assert.Equal(0, _dicomRequestContextAccessor.RequestContext.TotalDicomEgressToStorageBytes);
181+
await _storeOrchestrator.DidNotReceiveWithAnyArgs().StoreDicomInstanceEntryAsync(Arg.Any<IDicomInstanceEntry>(), Arg.Any<CancellationToken>());
177182
}
178183

179184
[Fact]
@@ -187,6 +192,8 @@ public async Task GivenADicomDatasetFailsToOpenDueToDicomValidationException_Whe
187192

188193
_storeResponseBuilder.DidNotReceiveWithAnyArgs().AddSuccess(default, DefaultStoreValidationResult, Partition.Default);
189194
_storeResponseBuilder.Received(1).AddFailure(null, TestConstants.ValidationFailureReasonCode);
195+
Assert.Equal(0, _dicomRequestContextAccessor.RequestContext.TotalDicomEgressToStorageBytes);
196+
await _storeOrchestrator.DidNotReceiveWithAnyArgs().StoreDicomInstanceEntryAsync(Arg.Any<IDicomInstanceEntry>(), Arg.Any<CancellationToken>());
190197
}
191198

192199
[Fact]
@@ -199,6 +206,8 @@ public async Task GivenAValidationError_WhenDropDataEnabled_ThenSucceedsWithErro
199206
dicomDataset.Add(DicomTag.StudyDate, "NotAValidStudyDate");
200207

201208
dicomInstanceEntry.GetDicomDatasetAsync(DefaultCancellationToken).Returns(dicomDataset);
209+
long bytesStored = 100L;
210+
_storeOrchestrator.StoreDicomInstanceEntryAsync(dicomInstanceEntry, DefaultCancellationToken).Returns(bytesStored);
202211

203212
// call
204213
StoreResponse response = await _storeServiceDropData.ProcessAsync(
@@ -235,6 +244,8 @@ await _storeOrchestrator
235244
dicomInstanceEntry,
236245
DefaultCancellationToken
237246
);
247+
248+
Assert.Equal(bytesStored, _dicomRequestContextAccessorLatestApi.RequestContext.TotalDicomEgressToStorageBytes);
238249
}
239250

240251
[Fact]
@@ -247,6 +258,8 @@ public async Task GivenAValidationErrorOnNonCoreTag_WhenDropDataEnabledAndFullDi
247258
dicomDataset.Add(DicomTag.StudyDate, "NotAValidStudyDate");
248259

249260
dicomInstanceEntry.GetDicomDatasetAsync(DefaultCancellationToken).Returns(dicomDataset);
261+
long bytesStored = 100L;
262+
_storeOrchestrator.StoreDicomInstanceEntryAsync(dicomInstanceEntry, DefaultCancellationToken).Returns(bytesStored);
250263

251264
// call
252265
StoreResponse response = await _storeServiceDropData.ProcessAsync(
@@ -283,6 +296,8 @@ await _storeOrchestrator
283296
dicomInstanceEntry,
284297
DefaultCancellationToken
285298
);
299+
300+
Assert.Equal(bytesStored, _dicomRequestContextAccessorLatestApi.RequestContext.TotalDicomEgressToStorageBytes);
286301
}
287302

288303
[Fact]
@@ -515,10 +530,12 @@ public async Task GivenAnExternalStoreExceptionWhenStoring_WhenProcessed_ThenExp
515530
}
516531

517532
[Fact]
518-
public async Task GivenMultipleDicomInstanceEntries_WhenProcessed_ThenCorrespondingEntryShouldBeAdded()
533+
public async Task GivenMultipleDicomInstanceEntriesWithFailure_WhenProcessed_ThenCorrespondingEntryShouldBeAdded()
519534
{
520535
IDicomInstanceEntry dicomInstanceEntryToSucceed = Substitute.For<IDicomInstanceEntry>();
521536
IDicomInstanceEntry dicomInstanceEntryToFail = Substitute.For<IDicomInstanceEntry>();
537+
long bytesStored = 100L;
538+
_storeOrchestrator.StoreDicomInstanceEntryAsync(Arg.Any<IDicomInstanceEntry>(), DefaultCancellationToken).Returns(bytesStored);
522539

523540
dicomInstanceEntryToSucceed.GetDicomDatasetAsync(DefaultCancellationToken).Returns(_dicomDataset1);
524541
dicomInstanceEntryToFail.GetDicomDatasetAsync(DefaultCancellationToken).Returns(_dicomDataset2);
@@ -535,6 +552,56 @@ public async Task GivenMultipleDicomInstanceEntries_WhenProcessed_ThenCorrespond
535552
_storeResponseBuilder.Received(1).AddSuccess(_dicomDataset1, DefaultStoreValidationResult, _dicomRequestContext.DataPartition);
536553
_storeResponseBuilder.Received(1).AddFailure(_dicomDataset2, TestConstants.ProcessingFailureReasonCode);
537554
Assert.Equal(2, _dicomRequestContextAccessor.RequestContext.PartCount);
555+
556+
await _storeOrchestrator
557+
.Received(1)
558+
.StoreDicomInstanceEntryAsync(
559+
dicomInstanceEntryToSucceed,
560+
DefaultCancellationToken
561+
);
562+
563+
await _storeOrchestrator
564+
.DidNotReceive()
565+
.StoreDicomInstanceEntryAsync(
566+
dicomInstanceEntryToFail,
567+
DefaultCancellationToken
568+
);
569+
570+
Assert.Equal(bytesStored, _dicomRequestContextAccessor.RequestContext.TotalDicomEgressToStorageBytes);
571+
}
572+
573+
[Fact]
574+
public async Task GivenMultipleDicomInstanceEntries_WhenProcessed_ThenTotalBytesTracked()
575+
{
576+
IDicomInstanceEntry dicomInstanceEntryToSucceed = Substitute.For<IDicomInstanceEntry>();
577+
IDicomInstanceEntry dicomInstanceEntryToSucceed2 = Substitute.For<IDicomInstanceEntry>();
578+
long bytesStored = 100L;
579+
long totalExpectedBytesStored = bytesStored * 2;
580+
_storeOrchestrator.StoreDicomInstanceEntryAsync(Arg.Any<IDicomInstanceEntry>(), DefaultCancellationToken).Returns(bytesStored);
581+
582+
dicomInstanceEntryToSucceed.GetDicomDatasetAsync(DefaultCancellationToken).Returns(_dicomDataset1);
583+
dicomInstanceEntryToSucceed2.GetDicomDatasetAsync(DefaultCancellationToken).Returns(_dicomDataset2);
584+
585+
await ExecuteAndValidateAsync(dicomInstanceEntryToSucceed, dicomInstanceEntryToSucceed2);
586+
587+
_storeResponseBuilder.Received(1).AddSuccess(_dicomDataset1, DefaultStoreValidationResult, _dicomRequestContext.DataPartition);
588+
_storeResponseBuilder.Received(1).AddSuccess(_dicomDataset2, DefaultStoreValidationResult, _dicomRequestContext.DataPartition);
589+
590+
await _storeOrchestrator
591+
.Received(1)
592+
.StoreDicomInstanceEntryAsync(
593+
dicomInstanceEntryToSucceed,
594+
DefaultCancellationToken
595+
);
596+
597+
await _storeOrchestrator
598+
.Received(1)
599+
.StoreDicomInstanceEntryAsync(
600+
dicomInstanceEntryToSucceed2,
601+
DefaultCancellationToken
602+
);
603+
604+
Assert.Equal(totalExpectedBytesStored, _dicomRequestContextAccessor.RequestContext.TotalDicomEgressToStorageBytes);
538605
}
539606

540607
[Fact]

src/Microsoft.Health.Dicom.Core/Features/Context/DicomRequestContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,4 +86,9 @@ public DicomRequestContext(
8686
public IDictionary<string, StringValues> RequestHeaders { get; }
8787

8888
public IDictionary<string, StringValues> ResponseHeaders { get; }
89+
90+
/// <summary>
91+
/// Egress bytes from Dicom server to other resources
92+
/// </summary>
93+
public long TotalDicomEgressToStorageBytes { get; set; }
8994
}

src/Microsoft.Health.Dicom.Core/Features/Context/IDicomRequestContext.cs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,9 @@ public interface IDicomRequestContext : IRequestContext
2828

2929
// Opportunity for the core to change based on the caller version
3030
int Version { get; set; }
31+
32+
/// <summary>
33+
/// Egress bytes from Dicom server to other resources
34+
/// </summary>
35+
long TotalDicomEgressToStorageBytes { get; set; }
3136
}

src/Microsoft.Health.Dicom.Core/Features/Store/StoreService.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ public async Task<StoreResponse> ProcessAsync(
115115
long len = length.GetValueOrDefault();
116116
// Update Telemetry
117117
_storeMeter.InstanceLength.Record(len);
118+
_dicomRequestContextAccessor.RequestContext.TotalDicomEgressToStorageBytes += len;
118119
}
119120
}
120121
finally

0 commit comments

Comments
 (0)