增加周期性邮件默认Culture,后台触发邮件报错通知企业微信

Test_IRC_Net8^2
hang 2026-02-12 03:24:58 -05:00
parent 048193e4f3
commit 3bdba35501
8 changed files with 75 additions and 18 deletions

View File

@ -15,12 +15,13 @@ using Hangfire.Storage;
using System.Linq; using System.Linq;
using Microsoft.EntityFrameworkCore; using Microsoft.EntityFrameworkCore;
using MassTransit.Mediator; using MassTransit.Mediator;
using Microsoft.Extensions.Configuration;
namespace IRaCIS.Core.API.HostService; namespace IRaCIS.Core.API.HostService;
public class HangfireHostService(IRecurringMessageScheduler _recurringMessageScheduler, public class HangfireHostService(IRecurringMessageScheduler _recurringMessageScheduler,
IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository, IRepository<TrialEmailNoticeConfig> _trialEmailNoticeConfigRepository,
IConfiguration _config,
IRepository<EmailNoticeConfig> _emailNoticeConfigrepository, IRepository<EmailNoticeConfig> _emailNoticeConfigrepository,
IMediator _mediator, IMediator _mediator,
ILogger<HangfireHostService> _logger) : IHostedService ILogger<HangfireHostService> _logger) : IHostedService
@ -56,6 +57,8 @@ public class HangfireHostService(IRecurringMessageScheduler _recurringMessageSch
} }
} }
string defaultCulture = _config.GetValue<string>("SystemEmailSendConfig:CronEmailDefaultCulture");
// 项目手动选择,周期性邮件 // 项目手动选择,周期性邮件
var taskInfoList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr == StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend) var taskInfoList = await _trialEmailNoticeConfigRepository.Where(t => t.Trial.TrialStatusStr == StaticData.TrialState.TrialOngoing && t.EmailCron != string.Empty && t.IsAutoSend)
.Select(t => new { t.Id, t.Code, TrialCode = t.Trial.TrialCode, t.EmailCron, t.BusinessScenarioEnum, t.TrialId }) .Select(t => new { t.Id, t.Code, TrialCode = t.Trial.TrialCode, t.EmailCron, t.BusinessScenarioEnum, t.TrialId })
@ -68,11 +71,11 @@ public class HangfireHostService(IRecurringMessageScheduler _recurringMessageSch
var trialId = task.TrialId; var trialId = task.TrialId;
HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, trialId, task.BusinessScenarioEnum, task.EmailCron); HangfireJobHelper.AddOrUpdateTrialCronJob(jobId, trialId, task.BusinessScenarioEnum, task.EmailCron, defaultCulture);
} }
// 系统邮件定时任务 // 系统邮件定时任务 要设置默认语言
var systemTaskInfoList = await _emailNoticeConfigrepository.Where(t => t.EmailCron != string.Empty && t.IsAutoSend) var systemTaskInfoList = await _emailNoticeConfigrepository.Where(t => t.EmailCron != string.Empty && t.IsAutoSend)
.Select(t => new { t.Id, t.Code, t.EmailCron, t.BusinessScenarioEnum, }) .Select(t => new { t.Id, t.Code, t.EmailCron, t.BusinessScenarioEnum, })
.ToListAsync(); .ToListAsync();
@ -82,7 +85,7 @@ public class HangfireHostService(IRecurringMessageScheduler _recurringMessageSch
//利用主键作为任务Id //利用主键作为任务Id
var jobId = $"{task.Id}_({task.BusinessScenarioEnum})"; var jobId = $"{task.Id}_({task.BusinessScenarioEnum})";
HangfireJobHelper.AddOrUpdateTimingCronJob(jobId, task.BusinessScenarioEnum, task.EmailCron); HangfireJobHelper.AddOrUpdateTimingCronJob(jobId, task.BusinessScenarioEnum, task.EmailCron, defaultCulture);
} }

View File

@ -81,6 +81,7 @@
"IsEnv_US": false, "IsEnv_US": false,
"IsOpenErrorNoticeEmail": false, "IsOpenErrorNoticeEmail": false,
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", "EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"CronEmailDefaultCulture": "zh-CN",
"ErrorNoticeEmailList": [ "872297557@qq.com" ] "ErrorNoticeEmailList": [ "872297557@qq.com" ]
}, },
"SystemPacsConfig": { "SystemPacsConfig": {

View File

@ -162,6 +162,7 @@
"IsOpenErrorNoticeEmail": false, "IsOpenErrorNoticeEmail": false,
// //
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", "EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"CronEmailDefaultCulture": "zh-CN",
// //
"ErrorNoticeEmailList": [ "872297557@qq.com" ] "ErrorNoticeEmailList": [ "872297557@qq.com" ]
}, },

View File

@ -87,6 +87,7 @@
"IsEnv_US": true, "IsEnv_US": true,
"IsOpenErrorNoticeEmail": false, "IsOpenErrorNoticeEmail": false,
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", "EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"CronEmailDefaultCulture": "en-US",
"ErrorNoticeEmailList": [ "872297557@qq.com" ] "ErrorNoticeEmailList": [ "872297557@qq.com" ]
}, },

View File

@ -93,6 +93,7 @@
"IsEnv_US": true, "IsEnv_US": true,
"IsOpenErrorNoticeEmail": false, "IsOpenErrorNoticeEmail": false,
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", "EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"CronEmailDefaultCulture": "en-US",
"ErrorNoticeEmailList": [ "872297557@qq.com" ] "ErrorNoticeEmailList": [ "872297557@qq.com" ]
}, },

View File

@ -100,6 +100,7 @@
"IsEnv_US": false, "IsEnv_US": false,
"IsOpenErrorNoticeEmail": false, "IsOpenErrorNoticeEmail": false,
"EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$", "EmailRegexStr": "^[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\\.[a-zA-Z]{2,}$",
"CronEmailDefaultCulture": "zh-CN",
"ErrorNoticeEmailList": [ "872297557@qq.com" ] "ErrorNoticeEmailList": [ "872297557@qq.com" ]
}, },

View File

@ -2,6 +2,7 @@
using IRaCIS.Core.Application.MassTransit.Consumer; using IRaCIS.Core.Application.MassTransit.Consumer;
using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Domain.Share;
using MassTransit.Mediator; using MassTransit.Mediator;
using System.Globalization;
namespace IRaCIS.Core.Application.Helper namespace IRaCIS.Core.Application.Helper
{ {
@ -57,25 +58,29 @@ namespace IRaCIS.Core.Application.Helper
} }
public static void AddOrUpdateTrialCronJob(string jobId, Guid trialId, EmailBusinessScenario businessScenario, string emailCron) public static void AddOrUpdateTrialCronJob(string jobId, Guid trialId, EmailBusinessScenario businessScenario, string emailCron,string defaultCulture="")
{ {
if (defaultCulture == "")
{
defaultCulture = CultureInfo.CurrentCulture.Name;
}
switch (businessScenario) switch (businessScenario)
{ {
case EmailBusinessScenario.QCTask: case EmailBusinessScenario.QCTask:
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new ImageQCRecurringEvent() { TrialId = trialId }, default), emailCron); HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new ImageQCRecurringEvent() { TrialId = trialId,CultureInfoName= defaultCulture }, default), emailCron);
break; break;
case EmailBusinessScenario.CRCToQCQuestion: case EmailBusinessScenario.CRCToQCQuestion:
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new CRCImageQuestionRecurringEvent() { TrialId = trialId }, default), emailCron); HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new CRCImageQuestionRecurringEvent() { TrialId = trialId, CultureInfoName = defaultCulture }, default), emailCron);
break; break;
case EmailBusinessScenario.QCToCRCImageQuestion: case EmailBusinessScenario.QCToCRCImageQuestion:
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new QCImageQuestionRecurringEvent() { TrialId = trialId }, default), emailCron); HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new QCImageQuestionRecurringEvent() { TrialId = trialId, CultureInfoName = defaultCulture }, default), emailCron);
break; break;
//加急阅片 10分钟 //加急阅片 10分钟
case EmailBusinessScenario.ExpeditedReading: case EmailBusinessScenario.ExpeditedReading:
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new UrgentIRUnReadTaskRecurringEvent() { TrialId = trialId }, default), emailCron); HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new UrgentIRUnReadTaskRecurringEvent() { TrialId = trialId, CultureInfoName = defaultCulture }, default), emailCron);
break; break;
default: default:
break; break;
@ -83,20 +88,25 @@ namespace IRaCIS.Core.Application.Helper
} }
public static void AddOrUpdateTimingCronJob(string jobId, EmailBusinessScenario businessScenario, string emailCron) public static void AddOrUpdateTimingCronJob(string jobId, EmailBusinessScenario businessScenario, string emailCron, string defaultCulture="")
{ {
if (defaultCulture == "")
{
defaultCulture = CultureInfo.CurrentCulture.Name;
}
switch (businessScenario) switch (businessScenario)
{ {
case EmailBusinessScenario.GeneralTraining_ExpirationNotification: case EmailBusinessScenario.GeneralTraining_ExpirationNotification:
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new SystemDocumentErverDayEvent() { }, default), emailCron); HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new SystemDocumentErverDayEvent() { CultureInfoName = defaultCulture }, default), emailCron);
break; break;
case EmailBusinessScenario.TrialTraining_ExpirationNotification: case EmailBusinessScenario.TrialTraining_ExpirationNotification:
Console.WriteLine("更新项目到期job"); Console.WriteLine("更新项目到期job");
HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new TrialDocumentErverDayEvent() { }, default), emailCron); HangfireJobHelper.AddOrUpdateCronJob<IMediator>(jobId, t => t.Send(new TrialDocumentErverDayEvent() { CultureInfoName = defaultCulture }, default), emailCron);
break; break;
default: default:

View File

@ -1,14 +1,16 @@
using System; using IRaCIS.Core.Application.Helper.OtherTool;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
using IRaCIS.Core.Domain.BaseModel; using IRaCIS.Core.Domain.BaseModel;
using IRaCIS.Core.Domain.Share; using IRaCIS.Core.Domain.Share;
using MassTransit; using MassTransit;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Logging; using Microsoft.Extensions.Logging;
using NPOI.SS.Formula.Functions; using Newtonsoft.Json;
using System;
using System.Globalization;
using System.Threading;
using System.Threading.Tasks;
public class ConsumeExceptionFilter<T>(ILogger<ConsumeExceptionFilter<T>> _logger) : IFilter<ConsumeContext<T>> where T : DomainEvent public class ConsumeExceptionFilter<T>(ILogger<ConsumeExceptionFilter<T>> _logger, IConfiguration _config) : IFilter<ConsumeContext<T>> where T : DomainEvent
{ {
public async Task Send(ConsumeContext<T> context, IPipe<ConsumeContext<T>> next) public async Task Send(ConsumeContext<T> context, IPipe<ConsumeContext<T>> next)
@ -23,6 +25,43 @@ public class ConsumeExceptionFilter<T>(ILogger<ConsumeExceptionFilter<T>> _logge
{ {
var errorInfo = $"Exception: {exception.Message}[{exception.StackTrace}]" + (exception.InnerException != null ? $" InnerException: {exception.InnerException.Message}[{exception.InnerException.StackTrace}]" : ""); var errorInfo = $"Exception: {exception.Message}[{exception.StackTrace}]" + (exception.InnerException != null ? $" InnerException: {exception.InnerException.Message}[{exception.InnerException.StackTrace}]" : "");
_logger.LogError(errorInfo); _logger.LogError(errorInfo);
try
{
bool isOpenWeComNotice = _config.GetValue<bool>("WeComNoticeConfig:IsOpenWeComNotice");
if (isOpenWeComNotice)
{
string webhook = _config["WeComNoticeConfig:WebhookUrl"] ?? string.Empty;
var uri = new Uri(_config["SystemEmailSendConfig:SiteUrl"]);
var baseUrl = uri.GetLeftPart(UriPartial.Authority);
var userList = _config.GetSection("WeComNoticeConfig:VueNoticeUserList").Get<string[]>();
// 🔔 异步告警(不要阻塞请求)
_ = WeComNotifier.SendAlertAsync(
webhook: webhook,
alert: new WeComAlert
{
Env = baseUrl,
UserName = "MassTransit 自动触发邮件",
Api = "",
Message = $"异常信息:{exception.Message} 堆栈信息:[{exception.StackTrace}",
AtUsers = userList ?? []
}
);
}
}
catch (Exception ex)
{
Log.Logger.Error($"模型验证过滤器里发送企业微信出现错误:{ex.Message}");
}
} }
} }