Skip to content

Commit 0e17838

Browse files
authored
Merge pull request #349 from Project-MONAI/patch/0.3.13
Merge release 0.3.13 into main
2 parents 67144dc + 7d43ce6 commit 0e17838

File tree

20 files changed

+79
-53
lines changed

20 files changed

+79
-53
lines changed

.github/.gitversion.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,4 +29,4 @@ branches:
2929
ignore:
3030
sha: []
3131
merge-message-formats: {}
32-
next-version: 0.3.11
32+
next-version: 0.3.12

docs/changelog.md

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,15 @@
1717

1818
# Changelog
1919

20+
## 0.3.13
21+
22+
[GitHub Milestone 0.3.13](https://github.com/Project-MONAI/monai-deploy-informatics-gateway/milestone/18)
23+
24+
- Fixes an issue where failure uploads caused payload to stuck in the queue and stops processing any incoming data.
25+
2026
## 0.3.12
2127

22-
[GitHub Milestone 0.3.11](https://github.com/Project-MONAI/monai-deploy-informatics-gateway/milestone/17)
28+
[GitHub Milestone 0.3.12](https://github.com/Project-MONAI/monai-deploy-informatics-gateway/milestone/17)
2329

2430
- Fixes exception handling for unavailable previously created dead-letter queues
2531

src/Api/MonaiApplicationEntity.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021-2022 MONAI Consortium
2+
* Copyright 2021-2023 MONAI Consortium
33
* Copyright 2019-2021 NVIDIA Corporation
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -15,7 +15,6 @@
1515
* limitations under the License.
1616
*/
1717

18-
using System;
1918
using System.Collections.Generic;
2019
using System.ComponentModel.DataAnnotations;
2120
using System.ComponentModel.DataAnnotations.Schema;

src/Api/Storage/Payload.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021-2022 MONAI Consortium
2+
* Copyright 2021-2023 MONAI Consortium
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.

src/Configuration/DicomWebConfiguration.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021-2022 MONAI Consortium
2+
* Copyright 2021-2023 MONAI Consortium
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -55,7 +55,8 @@ public class DicomWebConfiguration
5555
/// single POST request, therefore, the timeout value may be insignificant unless the load of the
5656
/// network affects the upload speed.
5757
/// </summary>
58-
public uint Timeout { get; set; } = 2;
58+
[ConfigurationKeyName("timeout")]
59+
public uint Timeout { get; set; } = 10;
5960

6061
public DicomWebConfiguration()
6162
{

src/InformaticsGateway/Logging/Log.3000.PayloadAssembler.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,7 @@ public static partial class Log
5454
[LoggerMessage(EventId = 3012, Level = LogLevel.Information, Message = "Bucket {key} created with timeout {timeout}s.")]
5555
public static partial void BucketCreated(this ILogger logger, string key, uint timeout);
5656

57-
[LoggerMessage(EventId = 3014, Level = LogLevel.Error, Message = "Payload deleted due to upload failure(s) {key}.")]
58-
public static partial void PayloadRemovedWithFailureUploads(this ILogger logger, string key);
57+
[LoggerMessage(EventId = 3014, Level = LogLevel.Error, Message = "Payload ({key}) with {totalNumberOfFiles} files deleted due to {failures} upload failure(s).")]
58+
public static partial void PayloadRemovedWithFailureUploads(this ILogger logger, string key, int totalNumberOfFiles, int failures);
5959
}
6060
}

src/InformaticsGateway/Services/Connectors/PayloadAssembler.cs

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021-2022 MONAI Consortium
2+
* Copyright 2021-2023 MONAI Consortium
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -17,6 +17,7 @@
1717
using System;
1818
using System.Collections.Concurrent;
1919
using System.Collections.Generic;
20+
using System.Linq;
2021
using System.Threading;
2122
using System.Threading.Tasks;
2223
using Ardalis.GuardClauses;
@@ -149,10 +150,10 @@ private async void OnTimedEvent(Object source, System.Timers.ElapsedEventArgs e)
149150
_logger.BucketRemoveError(key);
150151
}
151152
}
152-
else if (payload.AnyUploadFailures())
153+
else if (payload.IsUploadCompletedWithFailures())
153154
{
154155
_payloads.TryRemove(key, out _);
155-
_logger.PayloadRemovedWithFailureUploads(key);
156+
_logger.PayloadRemovedWithFailureUploads(key, payload.Count, payload.Files.Count(p => p.IsUploadFailed));
156157
}
157158
}
158159
}

src/InformaticsGateway/Services/Connectors/PayloadExtensions.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022 MONAI Consortium
2+
* Copyright 2022-2023 MONAI Consortium
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -28,9 +28,9 @@ public static bool IsUploadCompleted(this Payload payload)
2828
return payload.Files.All(p => p.IsUploaded);
2929
}
3030

31-
public static bool AnyUploadFailures(this Payload payload)
31+
public static bool IsUploadCompletedWithFailures(this Payload payload)
3232
{
33-
return payload.Files.Any(p => p.IsUploadFailed);
33+
return payload.Files.Count(p => p.IsUploadFailed) + payload.Files.Count(p => p.IsUploaded) == payload.Count; ;
3434
}
3535

3636
public static bool IsMoveCompleted(this Payload payload)

src/InformaticsGateway/Services/Http/InferenceController.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021-2022 MONAI Consortium
2+
* Copyright 2021-2023 MONAI Consortium
33
* Copyright 2019-2021 NVIDIA Corporation
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -90,7 +90,6 @@ public async Task<ActionResult> NewInferenceRequest([FromBody] InferenceRequest
9090
using var _ = _logger.BeginScope(new LoggingDataDictionary<string, object> { { "TransactionId", request.TransactionId } });
9191
try
9292
{
93-
9493
if (await _inferenceRequestRepository.ExistsAsync(request.TransactionId, HttpContext.RequestAborted).ConfigureAwait(false))
9594
{
9695
return Problem(title: "Conflict", statusCode: (int)HttpStatusCode.Conflict, detail: "An existing request with same transaction ID already exists.");

src/InformaticsGateway/Services/Storage/ObjectUploadService.cs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2021-2022 MONAI Consortium
2+
* Copyright 2021-2023 MONAI Consortium
33
* Copyright 2019-2021 NVIDIA Corporation
44
*
55
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -103,7 +103,7 @@ private async Task StartWorker(int thread, CancellationToken cancellationToken)
103103
{
104104
try
105105
{
106-
var item = await _uplaodQueue.Dequeue(cancellationToken);
106+
var item = await _uplaodQueue.Dequeue(cancellationToken).ConfigureAwait(false);
107107
await ProcessObject(item).ConfigureAwait(false);
108108
}
109109
catch (OperationCanceledException ex)
@@ -164,6 +164,7 @@ private async Task ProcessObject(FileStorageMetadata blob)
164164
}
165165
catch (Exception ex)
166166
{
167+
blob.SetFailed();
167168
_logger.FailedToUploadFile(blob.Id, ex);
168169
}
169170
finally

src/InformaticsGateway/Test/Services/Connectors/PayloadAssemblerTest.cs

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -116,18 +116,23 @@ public async Task GivenAPayloadAssembler_WhenDisposed_ExpectResourceToBeCleanedU
116116
}
117117

118118
[RetryFact(10, 200)]
119-
public async Task GivenAPayloadThatHasNotCompleteUploads_WhenProcessedByTimedEvent_ExpectToBeAddedToQueue()
119+
public async Task GivenAPayloadThatHasNotCompleteUploads_WhenProcessedByTimedEvent_ExpectToBeRemovedFromQueue()
120120
{
121121
var payloadAssembler = new PayloadAssembler(_options, _logger.Object, _serviceScopeFactory.Object);
122122

123-
var file = new TestStorageInfo(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "file1", ".txt");
124-
file.File.SetUploaded("bucket");
123+
var file1 = new TestStorageInfo(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "file1", ".txt");
124+
var file2 = new TestStorageInfo(Guid.NewGuid().ToString(), Guid.NewGuid().ToString(), "file1", ".txt");
125125

126-
await payloadAssembler.Queue("A", file, 1);
126+
await payloadAssembler.Queue("A", file1, 1);
127+
await payloadAssembler.Queue("A", file2, 1);
128+
129+
file1.SetFailed();
130+
file2.SetUploaded();
127131
await Task.Delay(1001);
128132
payloadAssembler.Dispose();
129133

130-
_repository.Verify(p => p.UpdateAsync(It.Is<Payload>(p => p.State == Payload.PayloadState.Move), It.IsAny<CancellationToken>()), Times.Once());
134+
_repository.Verify(p => p.UpdateAsync(It.Is<Payload>(p => p.State == Payload.PayloadState.Move), It.IsAny<CancellationToken>()), Times.Never());
135+
_logger.VerifyLoggingMessageBeginsWith($"Payload (A) with 2 files deleted due to 1 upload failure(s).", LogLevel.Error, Times.Once());
131136
}
132137

133138
[RetryFact(10, 200)]

src/InformaticsGateway/appsettings.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -112,4 +112,4 @@
112112
"InformaticsGatewayServerEndpoint": "http://localhost:5000",
113113
"DockerImagePrefix": "ghcr.io/project-monai/monai-deploy-informatics-gateway"
114114
}
115-
}
115+
}

src/Shared/Test/TestStorageInfo.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
*/
1616

1717
using Monai.Deploy.InformaticsGateway.Api.Storage;
18+
using Monai.Deploy.Messaging;
1819

1920
namespace Monai.Deploy.InformaticsGateway.SharedTest;
2021

@@ -33,4 +34,9 @@ public TestStorageInfo(string correlationsId, string identifier, string filePath
3334
public override string DataTypeDirectoryName => "dir";
3435

3536
public override StorageObjectMetadata File { get; set; }
37+
38+
public void SetUploaded()
39+
{
40+
File.SetUploaded("test");
41+
}
3642
}

tests/Integration.Test/Common/Hl7DataSink.cs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022 MONAI Consortium
2+
* Copyright 2022-2023 MONAI Consortium
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -14,6 +14,7 @@
1414
* limitations under the License.
1515
*/
1616

17+
using System.Diagnostics;
1718
using System.Net.Sockets;
1819
using System.Text;
1920
using Ardalis.GuardClauses;
@@ -95,6 +96,8 @@ private async Task SendOneAsync(DataProvider dataProvider, params object[] args)
9596

9697
private async Task SendBatchAsync(DataProvider dataProvider, params object[] args)
9798
{
99+
var stopwatch = new Stopwatch();
100+
stopwatch.Start();
98101
var messages = new List<byte>();
99102
foreach (var file in dataProvider.HL7Specs.Files.Keys)
100103
{
@@ -134,6 +137,8 @@ private async Task SendBatchAsync(DataProvider dataProvider, params object[] arg
134137
}
135138
} while (true);
136139
tcpClient.Close();
140+
stopwatch.Stop();
141+
_outputHelper.WriteLine($"Took {stopwatch.Elapsed.TotalSeconds}s to send {messages.Count} messages.");
137142
}
138143
}
139144
}

tests/Integration.Test/Features/DicomDimseScp.feature

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2022 MONAI Consortium
1+
# Copyright 2022-2023 MONAI Consortium
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -37,47 +37,47 @@ Feature: DICOM DIMSE SCP Services
3737

3838
@messaging_workflow_request @messaging
3939
Scenario Outline: Respond to C-STORE-RQ and group data by Study Instance UID
40-
Given a called AE Title named 'C-STORE-STUDY' that groups by '0020,000D' for 3 seconds
40+
Given a called AE Title named '<aet>' that groups by '0020,000D' for <timeout> seconds
4141
And a DICOM client configured with 300 seconds timeout
4242
And a DICOM client configured to send data over 1 associations and wait 0 between each association
4343
And <count> <modality> studies
44-
When a C-STORE-RQ is sent to 'Informatics Gateway' with AET 'C-STORE-STUDY' from 'TEST-RUNNER'
44+
When a C-STORE-RQ is sent to 'Informatics Gateway' with AET '<aet>' from 'TEST-RUNNER'
4545
Then a successful response should be received
4646
And <count> workflow requests sent to message broker
4747
And studies are uploaded to storage service
4848

4949
Examples:
50-
| modality | count |
51-
| MR | 1 |
52-
| CT | 1 |
53-
| MG | 2 |
54-
| US | 1 |
50+
| modality | count | aet | timeout |
51+
| MR | 1 | C-STORE-STUDY30 | 3 |
52+
| CT | 1 | C-STORE-STUDY30 | 3 |
53+
| MG | 2 | C-STORE-STUDY10 | 3 |
54+
| US | 1 | C-STORE-STUDY10 | 3 |
5555

5656
@messaging_workflow_request @messaging
5757
Scenario Outline: Respond to C-STORE-RQ and group data by Series Instance UID
58-
Given a called AE Title named 'C-STORE-SERIES' that groups by '0020,000E' for 3 seconds
58+
Given a called AE Title named '<aet>' that groups by '0020,000E' for <timeout> seconds
5959
And a DICOM client configured with 300 seconds timeout
6060
And a DICOM client configured to send data over 1 associations and wait 0 between each association
6161
And <study_count> <modality> studies with <series_count> series per study
62-
When a C-STORE-RQ is sent to 'Informatics Gateway' with AET 'C-STORE-SERIES' from 'TEST-RUNNER'
62+
When a C-STORE-RQ is sent to 'Informatics Gateway' with AET '<aet>' from 'TEST-RUNNER'
6363
Then a successful response should be received
6464
And <series_count> workflow requests sent to message broker
6565
And studies are uploaded to storage service
6666

6767
Examples:
68-
| modality | study_count | series_count |
69-
| MR | 1 | 2 |
70-
| CT | 1 | 2 |
71-
| MG | 1 | 3 |
72-
| US | 1 | 2 |
68+
| modality | study_count | series_count | aet | timeout |
69+
| MR | 1 | 2 | C-STORE-SER30 | 3 |
70+
| CT | 1 | 2 | C-STORE-SER30 | 3 |
71+
| MG | 1 | 3 | C-STORE-SER10 | 3 |
72+
| US | 1 | 2 | C-STORE-SER10 | 3 |
7373

7474
@messaging_workflow_request @messaging
7575
Scenario Outline: Respond to C-STORE-RQ and group data by Study Instance UID over multiple associations
76-
Given a called AE Title named 'C-STORE-STUDY' that groups by '0020,000D' for 5 seconds
76+
Given a called AE Title named 'C-STORE-MA' that groups by '0020,000D' for 5 seconds
7777
And a DICOM client configured with 300 seconds timeout
7878
And a DICOM client configured to send data over <series_count> associations and wait <seconds> between each association
7979
And <study_count> <modality> studies with <series_count> series per study
80-
When C-STORE-RQ are sent to 'Informatics Gateway' with AET 'C-STORE-STUDY' from 'TEST-RUNNER'
80+
When C-STORE-RQ are sent to 'Informatics Gateway' with AET 'C-STORE-MA' from 'TEST-RUNNER'
8181
Then a successful response should be received
8282
And <workflow_requests> workflow requests sent to message broker
8383
And studies are uploaded to storage service

tests/Integration.Test/Features/DicomWebStow.feature

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
# Copyright 2022 MONAI Consortium
1+
# Copyright 2022-2023 MONAI Consortium
22
#
33
# Licensed under the Apache License, Version 2.0 (the "License");
44
# you may not use this file except in compliance with the License.
@@ -39,8 +39,8 @@ Feature: DICOMweb STOW-RS Service
3939
And studies are uploaded to storage service
4040
Examples:
4141
| modality | count |
42-
| CT | 2 |
43-
| US | 1 |
42+
| MR | 1 |
43+
| MG | 2 |
4444

4545
@messaging_workflow_request @messaging
4646
Scenario: Triggers a new workflow via DICOMWeb STOW-RS

tests/Integration.Test/StepDefinitions/FhirDefinitions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022 MONAI Consortium
2+
* Copyright 2022-2023 MONAI Consortium
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -29,7 +29,7 @@ public class FhirDefinitions
2929
internal enum FileFormat
3030
{ Xml, Json };
3131

32-
internal static readonly TimeSpan WaitTimeSpan = TimeSpan.FromMinutes(2);
32+
internal static readonly TimeSpan WaitTimeSpan = TimeSpan.FromMinutes(3);
3333
private readonly InformaticsGatewayConfiguration _informaticsGatewayConfiguration;
3434
private readonly RabbitMqConsumer _receivedMessages;
3535
private readonly DataProvider _dataProvider;

tests/Integration.Test/StepDefinitions/HealthLevel7Definitions.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright 2022 MONAI Consortium
2+
* Copyright 2022-2023 MONAI Consortium
33
*
44
* Licensed under the Apache License, Version 2.0 (the "License");
55
* you may not use this file except in compliance with the License.
@@ -73,7 +73,7 @@ public void ThenAcknowledgementAreReceived()
7373
[Then(@"a workflow requests sent to message broker")]
7474
public async Task ThenAWorkflowRequestIsSentToMessageBrokerAsync()
7575
{
76-
(await _receivedMessages.WaitforAsync(_dataProvider.HL7Specs.Files.Count, WaitTimeSpan)).Should().BeTrue();
76+
(await _receivedMessages.WaitforAsync(1, WaitTimeSpan)).Should().BeTrue();
7777
}
7878

7979
[Then(@"messages are uploaded to storage service")]

tests/Integration.Test/appsettings.json

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,9 @@
2020
"logDataPDUs": false
2121
}
2222
},
23+
"dicomWeb": {
24+
"timeout": 10
25+
},
2326
"messaging": {
2427
"publisherServiceAssemblyName": "Monai.Deploy.Messaging.RabbitMQ.RabbitMQMessagePublisherService, Monai.Deploy.Messaging.RabbitMQ",
2528
"publisherSettings": {
@@ -83,4 +86,4 @@
8386
"InformaticsGatewayServerEndpoint": "http://127.0.0.1:5000",
8487
"DockerImagePrefix": "ghcr.io/project-monai/monai-deploy-informatics-gateway"
8588
}
86-
}
89+
}

tests/Integration.Test/study.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,8 @@
1010
"CT": {
1111
"SeriesMin": 1,
1212
"SeriesMax": 2,
13-
"InstanceMin": 60,
14-
"InstanceMax": 1000,
13+
"InstanceMin": 50,
14+
"InstanceMax": 300,
1515
"SizeMin": 0.5,
1616
"SizeMax": 1
1717
},

0 commit comments

Comments
 (0)