修改接收转发多线程配置
continuous-integration/drone/push Build is passing
Details
continuous-integration/drone/push Build is passing
Details
parent
106916f7ad
commit
841f1892d4
|
|
@ -14,6 +14,7 @@ using MassTransit;
|
||||||
using MassTransit.NewIdProviders;
|
using MassTransit.NewIdProviders;
|
||||||
using Microsoft.AspNetCore.HttpOverrides;
|
using Microsoft.AspNetCore.HttpOverrides;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
|
using Microsoft.Identity.Client;
|
||||||
using Panda.DynamicWebApi;
|
using Panda.DynamicWebApi;
|
||||||
using Serilog;
|
using Serilog;
|
||||||
using Serilog.Events;
|
using Serilog.Events;
|
||||||
|
|
@ -218,6 +219,9 @@ else
|
||||||
|
|
||||||
DicomSetupBuilder.UseServiceProvider(app.Services);
|
DicomSetupBuilder.UseServiceProvider(app.Services);
|
||||||
|
|
||||||
|
// Program.cs
|
||||||
|
IRCAppConfig.Configuration = builder.Configuration;
|
||||||
|
|
||||||
|
|
||||||
var logger = app.Services.GetService<Microsoft.Extensions.Logging.ILogger<Program>>();
|
var logger = app.Services.GetService<Microsoft.Extensions.Logging.ILogger<Program>>();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -28,6 +28,7 @@ using FellowOakDicom.IO.Buffer;
|
||||||
using System.Diagnostics.CodeAnalysis;
|
using System.Diagnostics.CodeAnalysis;
|
||||||
using FellowOakDicom.Network.Client;
|
using FellowOakDicom.Network.Client;
|
||||||
using MassTransit.Futures.Contracts;
|
using MassTransit.Futures.Contracts;
|
||||||
|
using Microsoft.Identity.Client;
|
||||||
|
|
||||||
namespace IRaCIS.Core.SCP.Service
|
namespace IRaCIS.Core.SCP.Service
|
||||||
{
|
{
|
||||||
|
|
@ -36,6 +37,10 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
{
|
{
|
||||||
public bool IsSupportThirdService { get; set; }
|
public bool IsSupportThirdService { get; set; }
|
||||||
|
|
||||||
|
public bool IsForwardImageMultiThread { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
public List<string> CalledAEList { get; set; }
|
public List<string> CalledAEList { get; set; }
|
||||||
|
|
||||||
public string ServerPort { get; set; }
|
public string ServerPort { get; set; }
|
||||||
|
|
@ -50,6 +55,11 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
public string IP { get; set; }
|
public string IP { get; set; }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static class IRCAppConfig
|
||||||
|
{
|
||||||
|
public static IConfiguration Configuration { get; set; }
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -77,6 +87,8 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
private List<ThirdDestinationAE> ThirdDestinationAEList { get; set; }
|
private List<ThirdDestinationAE> ThirdDestinationAEList { get; set; }
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private static readonly DicomTransferSyntax[] _acceptedTransferSyntaxes = new DicomTransferSyntax[]
|
private static readonly DicomTransferSyntax[] _acceptedTransferSyntaxes = new DicomTransferSyntax[]
|
||||||
{
|
{
|
||||||
DicomTransferSyntax.ExplicitVRLittleEndian,
|
DicomTransferSyntax.ExplicitVRLittleEndian,
|
||||||
|
|
@ -103,6 +115,22 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
DicomTransferSyntax.ImplicitVRLittleEndian
|
DicomTransferSyntax.ImplicitVRLittleEndian
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// 定义一个静态信号量,控制同时最多 N 个转发线程
|
||||||
|
|
||||||
|
private static SemaphoreSlim _forwardLimiter;
|
||||||
|
|
||||||
|
// ✅ 静态构造函数(只执行一次,全局初始化)
|
||||||
|
static CStoreSCPService()
|
||||||
|
{
|
||||||
|
// 默认单线程
|
||||||
|
|
||||||
|
var maxThreads = IRCAppConfig.Configuration.GetValue<int>("DicomSCPServiceConfig:MultiThreadCount", 1);
|
||||||
|
|
||||||
|
_forwardLimiter = new SemaphoreSlim(maxThreads);
|
||||||
|
|
||||||
|
Log.Logger.Information($"初始化 DICOM 转发线程限制为: {maxThreads}");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public CStoreSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies, IServiceProvider injectServiceProvider)
|
public CStoreSCPService(INetworkStream stream, Encoding fallbackEncoding, Microsoft.Extensions.Logging.ILogger log, DicomServiceDependencies dependencies, IServiceProvider injectServiceProvider)
|
||||||
: base(stream, fallbackEncoding, log, dependencies)
|
: base(stream, fallbackEncoding, log, dependencies)
|
||||||
|
|
@ -306,6 +334,43 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private async Task<DicomStatus> ForwardToThirdPartyAsync(DicomCStoreRequest request, ThirdDestinationAE findDestination)
|
||||||
|
{
|
||||||
|
await _forwardLimiter.WaitAsync(); // 限制并发数量
|
||||||
|
try
|
||||||
|
{
|
||||||
|
var forwardRequest = new DicomCStoreRequest(request.File.Clone());
|
||||||
|
|
||||||
|
var client = DicomClientFactory.Create(
|
||||||
|
findDestination.IP,
|
||||||
|
findDestination.Port,
|
||||||
|
false,
|
||||||
|
DicomSCPServiceConfig.CalledAEList.First(),
|
||||||
|
findDestination.Name);
|
||||||
|
|
||||||
|
DicomStatus finalStatus = DicomStatus.Success;
|
||||||
|
|
||||||
|
forwardRequest.OnResponseReceived += (rq, rp) =>
|
||||||
|
{
|
||||||
|
Log.Logger.Information($"Forwarded C-STORE Response: {rq.SOPInstanceUID} {rp.Status}");
|
||||||
|
finalStatus = rp.Status; // 记录目标 PACS 返回状态
|
||||||
|
};
|
||||||
|
|
||||||
|
await client.AddRequestAsync(forwardRequest);
|
||||||
|
await client.SendAsync();
|
||||||
|
|
||||||
|
return finalStatus; // 返回实际状态
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
Log.Logger.Error("Error forwarding C-STORE: " + ex.Message);
|
||||||
|
return DicomStatus.ProcessingFailure; // 出错返回失败状态
|
||||||
|
}
|
||||||
|
finally
|
||||||
|
{
|
||||||
|
_forwardLimiter.Release();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
public async Task<DicomCStoreResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
|
public async Task<DicomCStoreResponse> OnCStoreRequestAsync(DicomCStoreRequest request)
|
||||||
|
|
@ -336,38 +401,25 @@ namespace IRaCIS.Core.SCP.Service
|
||||||
{
|
{
|
||||||
_isCurrentThirdForward = true;
|
_isCurrentThirdForward = true;
|
||||||
|
|
||||||
_ = Task.Run(async () =>
|
|
||||||
{
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
var findDestination = ThirdDestinationAEList.FirstOrDefault(t => t.Name == cmoveInfo.DestinationAE);
|
var findDestination = ThirdDestinationAEList.FirstOrDefault(t => t.Name == cmoveInfo.DestinationAE);
|
||||||
|
|
||||||
var forwardRequest = new DicomCStoreRequest(request.File.Clone());
|
if (DicomSCPServiceConfig.IsForwardImageMultiThread)
|
||||||
|
|
||||||
// 创建客户端连接到目标 PACS
|
|
||||||
var client = DicomClientFactory.Create(findDestination.IP, findDestination.Port, false, DicomSCPServiceConfig.CalledAEList.First(), cmoveInfo.DestinationAE);
|
|
||||||
|
|
||||||
// 可以加入 OnResponseReceived 来处理目标 PACS 返回状态
|
|
||||||
forwardRequest.OnResponseReceived += (rq, rp) =>
|
|
||||||
{
|
{
|
||||||
Log.Logger.Information($"Forwarded C-STORE Response: {rq.SOPInstanceUID} {rp.Status}");
|
// 多线程模式,异步执行
|
||||||
|
_ = Task.Run(() => ForwardToThirdPartyAsync(request, findDestination));
|
||||||
|
|
||||||
};
|
// 立即返回 Success
|
||||||
|
|
||||||
await client.AddRequestAsync(forwardRequest);
|
|
||||||
await client.SendAsync();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
Log.Logger.Error("Error forwarding C-STORE: " + ex.Message);
|
|
||||||
}
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
// 立即返回 Success 给原发送方
|
|
||||||
return new DicomCStoreResponse(request, DicomStatus.Success);
|
return new DicomCStoreResponse(request, DicomStatus.Success);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// 单线程模式,同步等待完成
|
||||||
|
var responseStatus = await ForwardToThirdPartyAsync(request, findDestination);
|
||||||
|
|
||||||
|
return new DicomCStoreResponse(request, responseStatus);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,6 +25,8 @@
|
||||||
},
|
},
|
||||||
"DicomSCPServiceConfig": {
|
"DicomSCPServiceConfig": {
|
||||||
"IsSupportThirdService": true,
|
"IsSupportThirdService": true,
|
||||||
|
"IsForwardImageMultiThread": true,
|
||||||
|
"MultiThreadCount":10,
|
||||||
"CalledAEList": [
|
"CalledAEList": [
|
||||||
"HIRAE",
|
"HIRAE",
|
||||||
"STORESCP"
|
"STORESCP"
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue