修改接收转发多线程配置
continuous-integration/drone/push Build is passing Details

Test_HIR_Net8
hang 2025-11-03 13:12:11 +08:00
parent 106916f7ad
commit 841f1892d4
3 changed files with 85 additions and 27 deletions

View File

@ -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>>();

View File

@ -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);
}
}
} }

View File

@ -25,6 +25,8 @@
}, },
"DicomSCPServiceConfig": { "DicomSCPServiceConfig": {
"IsSupportThirdService": true, "IsSupportThirdService": true,
"IsForwardImageMultiThread": true,
"MultiThreadCount":10,
"CalledAEList": [ "CalledAEList": [
"HIRAE", "HIRAE",
"STORESCP" "STORESCP"