Skip to content

Commit 50245ab

Browse files
committed
gh-56 fix to read all DICOM header when loading from stream
- fix issue when exporting multiple files, only one get exported
1 parent 9e523a7 commit 50245ab

File tree

6 files changed

+63
-41
lines changed

6 files changed

+63
-41
lines changed

src/InformaticsGateway/Common/DicomToolkit.cs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,8 @@ public DicomFile Load(byte[] fileContent)
101101
Guard.Against.NullOrEmpty(fileContent, nameof(fileContent));
102102

103103
using var stream = new MemoryStream(fileContent);
104-
var dicomFile = DicomFile.Open(stream);
104+
var dicomFile = DicomFile.Open(stream, FileReadOption.ReadAll);
105+
105106
if (dicomFile is null)
106107
{
107108
throw new DicomDataException("Invalid DICOM content");

src/InformaticsGateway/Services/Export/DicomWebExportService.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,7 +59,7 @@ internal class DicomWebExportService : ExportServiceBase
5959
private readonly IOptions<InformaticsGatewayConfiguration> _configuration;
6060
private readonly IDicomToolkit _dicomToolkit;
6161

62-
protected override int Concurrentcy { get; }
62+
protected override int Concurrency { get; }
6363
public override string RoutingKey { get; }
6464
public override string ServiceName => "DICOMweb Export Service";
6565

@@ -81,7 +81,7 @@ public DicomWebExportService(
8181
_dicomToolkit = dicomToolkit ?? throw new ArgumentNullException(nameof(dicomToolkit));
8282

8383
RoutingKey = $"{configuration.Value.Messaging.Topics.ExportRequestPrefix}.{configuration.Value.DicomWeb.AgentName}";
84-
Concurrentcy = configuration.Value.DicomWeb.MaximumNumberOfConnection;
84+
Concurrency = configuration.Value.DicomWeb.MaximumNumberOfConnection;
8585
}
8686

8787
protected override async Task<ExportRequestDataMessage> ExportDataBlockCallback(ExportRequestDataMessage exportRequestData, CancellationToken cancellationToken)
@@ -137,10 +137,10 @@ await Policy
137137
_logger.Log(LogLevel.Error, exception, $"Error exporting to DICOMweb destination. Waiting {timeSpan} before next retry. Retry attempt {retryCount}.");
138138
})
139139
.ExecuteAsync(async () =>
140-
{
141-
var result = await dicomWebClient.Stow.Store(new List<DicomFile> { dicomFile }, cancellationToken);
142-
CheckAndLogResult(result);
143-
});
140+
{
141+
var result = await dicomWebClient.Stow.Store(new List<DicomFile> { dicomFile }, cancellationToken);
142+
CheckAndLogResult(result);
143+
});
144144
}
145145
catch (Exception ex)
146146
{

src/InformaticsGateway/Services/Export/ExportRequestDataMessage.cs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,12 +55,15 @@ public string Destination
5555
get { return _exportRequest.Destination; }
5656
}
5757

58-
public ExportRequestDataMessage(ExportRequestMessage exportRequest)
58+
public string Filename { get; }
59+
60+
public ExportRequestDataMessage(ExportRequestMessage exportRequest, string filename)
5961
{
6062
IsFailed = false;
6163
Messages = new List<string>();
6264

6365
_exportRequest = exportRequest ?? throw new System.ArgumentNullException(nameof(exportRequest));
66+
Filename = filename ?? throw new System.ArgumentNullException(nameof(filename));
6467
}
6568

6669
public void SetData(byte[] data)

src/InformaticsGateway/Services/Export/ExportServiceBase.cs

Lines changed: 46 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -63,12 +63,12 @@ public abstract class ExportServiceBase : IHostedService, IMonaiService
6363
private readonly IMessageBrokerSubscriberService _messageSubscriber;
6464
private readonly IMessageBrokerPublisherService _messagePublisher;
6565
private readonly IServiceScope _scope;
66-
private readonly Dictionary<string, ExportRequestMessage> _exportRequets;
66+
private readonly Dictionary<string, ExportRequestMessage> _exportRequests;
6767
private readonly string _exportQueueName;
6868
private TransformManyBlock<ExportRequestMessage, ExportRequestDataMessage> _exportFlow;
6969

7070
public abstract string RoutingKey { get; }
71-
protected abstract int Concurrentcy { get; }
71+
protected abstract int Concurrency { get; }
7272
public ServiceStatus Status { get; set; } = ServiceStatus.Unknown;
7373
public abstract string ServiceName { get; }
7474

@@ -102,7 +102,7 @@ public ExportServiceBase(
102102
_messageSubscriber = _scope.ServiceProvider.GetRequiredService<IMessageBrokerSubscriberService>();
103103
_messagePublisher = _scope.ServiceProvider.GetRequiredService<IMessageBrokerPublisherService>();
104104

105-
_exportRequets = new Dictionary<string, ExportRequestMessage>();
105+
_exportRequests = new Dictionary<string, ExportRequestMessage>();
106106
_exportQueueName = _configuration.Messaging.Topics.ExportRequestQueue;
107107
}
108108

@@ -131,7 +131,7 @@ private void SetupExportFlow(CancellationToken cancellationToken)
131131
{
132132
var executionOptions = new ExecutionDataflowBlockOptions
133133
{
134-
MaxDegreeOfParallelism = Concurrentcy,
134+
MaxDegreeOfParallelism = Concurrency,
135135
MaxMessagesPerTask = 1,
136136
CancellationToken = cancellationToken
137137
};
@@ -184,11 +184,22 @@ private void OnMessageReceivedCallback(MessageReceivedEventArgs eventArgs)
184184
_messageSubscriber.Reject(eventArgs.Message);
185185
return;
186186
}
187-
var exportRequest = eventArgs.Message.ConvertTo<ExportRequestMessage>();
188-
exportRequest.MessageId = eventArgs.Message.MessageId;
189187

190-
_exportRequets.Add(exportRequest.ExportTaskId, exportRequest);
191-
_exportFlow.Post(exportRequest);
188+
lock (SyncRoot)
189+
{
190+
var exportRequest = eventArgs.Message.ConvertTo<ExportRequestMessage>();
191+
if (_exportRequests.ContainsKey(exportRequest.ExportTaskId))
192+
{
193+
_logger.Log(LogLevel.Warning, $"The export request {exportRequest.ExportTaskId} is already queued for export.");
194+
return;
195+
}
196+
197+
exportRequest.MessageId = eventArgs.Message.MessageId;
198+
exportRequest.DeliveryTag = eventArgs.Message.DeliveryTag;
199+
200+
_exportRequests.Add(exportRequest.ExportTaskId, exportRequest);
201+
_exportFlow.Post(exportRequest);
202+
}
192203
}
193204

194205
private IEnumerable<ExportRequestDataMessage> DownloadPayloadActionCallback(ExportRequestMessage exportRequest, CancellationToken cancellationToken)
@@ -198,31 +209,33 @@ private IEnumerable<ExportRequestDataMessage> DownloadPayloadActionCallback(Expo
198209
var scope = _serviceScopeFactory.CreateScope();
199210
var storageService = scope.ServiceProvider.GetRequiredService<IStorageService>();
200211

201-
var exportRequestData = new ExportRequestDataMessage(exportRequest);
202212
foreach (var file in exportRequest.Files)
203213
{
214+
var exportRequestData = new ExportRequestDataMessage(exportRequest, file);
204215
try
205216
{
206217
_logger.Log(LogLevel.Debug, $"Downloading file {file}...");
207218
Policy
208-
.Handle<Exception>()
209-
.WaitAndRetry(
210-
_configuration.Export.Retries.RetryDelays,
211-
(exception, timeSpan, retryCount, context) =>
212-
{
213-
_logger.Log(LogLevel.Error, exception, $"Error downloading payload. Waiting {timeSpan} before next retry. Retry attempt {retryCount}.");
214-
})
215-
.Execute(() =>
216-
{
217-
storageService.GetObject(_configuration.Storage.StorageServiceBucketName, file, (stream) =>
218-
{
219-
_logger.Log(LogLevel.Debug, $"Copying file {file}...");
220-
using var memoryStream = new MemoryStream();
221-
stream.CopyTo(memoryStream);
222-
exportRequestData.SetData(memoryStream.ToArray());
223-
_logger.Log(LogLevel.Debug, $"File {file} ready for export...");
224-
}, cancellationToken).Wait();
225-
});
219+
.Handle<Exception>()
220+
.WaitAndRetry(
221+
_configuration.Export.Retries.RetryDelays,
222+
(exception, timeSpan, retryCount, context) =>
223+
{
224+
_logger.Log(LogLevel.Error, exception, $"Error downloading payload. Waiting {timeSpan} before next retry. Retry attempt {retryCount}.");
225+
})
226+
.Execute(() =>
227+
{
228+
_logger.Log(LogLevel.Debug, $"Downloading {file}...");
229+
var task = storageService.GetObject(_configuration.Storage.StorageServiceBucketName, file, (stream) =>
230+
{
231+
using var memoryStream = new MemoryStream();
232+
stream.CopyTo(memoryStream);
233+
exportRequestData.SetData(memoryStream.ToArray());
234+
}, cancellationToken);
235+
236+
task.Wait();
237+
_logger.Log(LogLevel.Debug, $"File {file} ready for export.");
238+
});
226239
}
227240
catch (Exception ex)
228241
{
@@ -239,7 +252,7 @@ private void ReportingActionBlock(ExportRequestDataMessage exportRequestData)
239252
{
240253
using var loggerScope = _logger.BeginScope(new LoggingDataDictionary<string, object> { { "ExportTaskId", exportRequestData.ExportTaskId }, { "CorrelationId", exportRequestData.CorrelationId } });
241254

242-
var exportRequest = _exportRequets[exportRequestData.ExportTaskId];
255+
var exportRequest = _exportRequests[exportRequestData.ExportTaskId];
243256
lock (SyncRoot)
244257
{
245258
if (exportRequestData.IsFailed)
@@ -300,6 +313,11 @@ private void ReportingActionBlock(ExportRequestDataMessage exportRequestData)
300313
_logger.Log(LogLevel.Information, $"Publishing export complete message.");
301314
_messagePublisher.Publish(_configuration.Messaging.Topics.ExportComplete, jsonMessage.ToMessage());
302315
});
316+
317+
lock(SyncRoot)
318+
{
319+
_exportRequests.Remove(exportRequestData.ExportTaskId);
320+
}
303321
}
304322
}
305323
}

src/InformaticsGateway/Services/Export/ScuExportService.cs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ internal class ScuExportService : ExportServiceBase
5252
private readonly IOptions<InformaticsGatewayConfiguration> _configuration;
5353
private readonly IDicomToolkit _dicomToolkit;
5454

55-
protected override int Concurrentcy { get; }
55+
protected override int Concurrency { get; }
5656
public override string RoutingKey { get; }
5757
public override string ServiceName => "DICOM Export Service";
5858

@@ -70,12 +70,12 @@ public ScuExportService(
7070
_dicomToolkit = dicomToolkit ?? throw new ArgumentNullException(nameof(dicomToolkit));
7171

7272
RoutingKey = $"{configuration.Value.Messaging.Topics.ExportRequestPrefix}.{_configuration.Value.Dicom.Scu.AgentName}";
73-
Concurrentcy = _configuration.Value.Dicom.Scu.MaximumNumberOfAssociations;
73+
Concurrency = _configuration.Value.Dicom.Scu.MaximumNumberOfAssociations;
7474
}
7575

7676
protected override async Task<ExportRequestDataMessage> ExportDataBlockCallback(ExportRequestDataMessage exportRequestData, CancellationToken cancellationToken)
7777
{
78-
using var loggerScope = _logger.BeginScope(new LoggingDataDictionary<string, object> { { "ExportTaskId", exportRequestData.ExportTaskId }, { "CorrelationId", exportRequestData.CorrelationId } });
78+
using var loggerScope = _logger.BeginScope(new LoggingDataDictionary<string, object> { { "ExportTaskId", exportRequestData.ExportTaskId }, { "CorrelationId", exportRequestData.CorrelationId }, { "Filename", exportRequestData.Filename } });
7979

8080
var manualResetEvent = new ManualResetEvent(false);
8181
IDicomClient client = null;

src/InformaticsGateway/Test/Services/Export/ExportServiceBaseTest.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ public class TestExportService : ExportServiceBase
3636
public event EventHandler ExportDataBlockCalled;
3737

3838
public bool ExportShallFail = false;
39-
protected override int Concurrentcy => 1;
39+
protected override int Concurrency => 1;
4040
public override string RoutingKey => AgentName;
4141
public override string ServiceName { get => "Test Export Service"; }
4242

@@ -260,4 +260,4 @@ private async Task StopAndVerify(TestExportService service)
260260
Thread.Sleep(250);
261261
}
262262
}
263-
}
263+
}

0 commit comments

Comments
 (0)