feat: 新增消息Outbox机制、雪花ID配置优化及多项功能完善

1.  新增数据库唯一约束和Message_Outbox表脚本
2.  新增雪花ID、Hangfire存储、MQ重试等配置实体
3.  重构各项目雪花ID生成逻辑,改为从配置读取WorkerId
4.  优化积分服务分页查询、用户背包更新逻辑
5.  新增JWT令牌Redis过期刷新逻辑
6.  完善RabbitMQ死信队列消息头信息
7.  新增可靠MQ消息发布服务和Outbox派发后台服务
8.  替换原有RabbitMQ直接发送为Outbox可靠发布
9.  优化签到服务逻辑,新增重复签到校验和补签卡扣减逻辑
10. 修复自动铺码消费逻辑,新增点阵页预占和释放机制
This commit is contained in:
glz
2026-07-10 10:44:00 +08:00
parent 685a8aeaec
commit cbdee5068a
33 changed files with 693 additions and 152 deletions

View File

@ -48,6 +48,8 @@ public class AutoDotCodeConsumer(
using var scope = scopeFactory.CreateScope();
var dbContext = scope.ServiceProvider.GetRequiredService<ISqlSugarClient>();
JournalPagePrintDto? request = null;
List<long> reservedDotDetailIds = [];
var dotPagesCommitted = false;
try
{
@ -135,6 +137,21 @@ public class AutoDotCodeConsumer(
}
var dotFileDetailPageName = dotFileDetailList.Select(x => x.PageName).OrderBy(x => x).ToArray();
reservedDotDetailIds = dotFileDetailList.Select(x => x.Id).ToList();
var reservedRows = await dbContext.Updateable<DotFileDetail>()
.SetColumns(x => x.IsUse == true)
.SetColumns(x => x.UpdatedAt == DateTime.Now)
.Where(x => reservedDotDetailIds.Contains(x.Id) && !x.IsUse)
.ExecuteCommandAsync(cancellationToken);
if (reservedRows != reservedDotDetailIds.Count)
{
logger.LogError("点阵页码预占失败DotId: {DotId}, Need: {Need}, Reserved: {Reserved}", dotId, reservedDotDetailIds.Count, reservedRows);
await ReleaseReservedDotPagesAsync(dbContext, reservedDotDetailIds, cancellationToken);
reservedDotDetailIds.Clear();
await TryCallbackCodeFailAsync(request, cancellationToken, dotFileDetailPageName);
return;
}
var pageStr = "{" + $"[{dotFileDetailList[0].PageName},{pageNumMax}]" + "}";
var arguments = $"-sMode=Generate -sPDF=\"{uploadFilePath}\" -sLIC=\"{xmlPath}\" -pStart=1 -oPDF=\"{downloadFilePath}\" -dPageAddr=1 -dPrint={dPrint} -dDotSize=40 -dType=0 -dOutFile=0 -dControlPageNum={pageStr}";
var printResult = await ExecutePrintToolAsync(exePath, printToolDirectory, arguments, cancellationToken);
@ -142,6 +159,8 @@ public class AutoDotCodeConsumer(
if (printResult.Timeout || printResult.ExitCode != 0)
{
logger.LogError("执行 PrintTool.exe 失败,退出码:{ExitCode},错误信息:{ErrorMessage}", printResult.ExitCode, printResult.Error);
await ReleaseReservedDotPagesAsync(dbContext, reservedDotDetailIds, cancellationToken);
reservedDotDetailIds.Clear();
await TryCallbackCodeFailAsync(request, cancellationToken, dotFileDetailPageName);
return;
}
@ -154,6 +173,8 @@ public class AutoDotCodeConsumer(
if (!ValidatePrintOutput(printResult.Output, dotFileDetailPageName, dPrint))
{
await ReleaseReservedDotPagesAsync(dbContext, reservedDotDetailIds, cancellationToken);
reservedDotDetailIds.Clear();
await TryCallbackCodeFailAsync(request, cancellationToken, dotFileDetailPageName);
return;
}
@ -189,9 +210,12 @@ public class AutoDotCodeConsumer(
.Where(x => x.Id == dotId)
.ExecuteCommandAsync();
});
dotPagesCommitted = true;
}
else
{
await ReleaseReservedDotPagesAsync(dbContext, reservedDotDetailIds, cancellationToken);
reservedDotDetailIds.Clear();
logger.LogError("回调接口修改书籍状态失败JournalId: {JournalId},接口返回消息:{Message}", statusModel.JournalId, callbackResponse.Message);
}
}
@ -205,6 +229,11 @@ public class AutoDotCodeConsumer(
logger.LogError(ex, "自动铺码处理失败");
if (request != null)
{
if (!dotPagesCommitted && reservedDotDetailIds.Count > 0)
{
await ReleaseReservedDotPagesAsync(dbContext, reservedDotDetailIds, CancellationToken.None);
}
await TryCallbackCodeFailAsync(request, CancellationToken.None);
}
}
@ -329,6 +358,20 @@ public class AutoDotCodeConsumer(
}
}
private static async Task ReleaseReservedDotPagesAsync(ISqlSugarClient dbContext, List<long> dotDetailIds, CancellationToken cancellationToken)
{
if (dotDetailIds.Count == 0)
{
return;
}
await dbContext.Updateable<DotFileDetail>()
.SetColumns(x => x.IsUse == false)
.SetColumns(x => x.UpdatedAt == DateTime.Now)
.Where(x => dotDetailIds.Contains(x.Id))
.ExecuteCommandAsync(cancellationToken);
}
private static JournalPagePrintDto BuildFailResponse(JournalPagePrintDto request, string[]? pageNo = null)
{
return new JournalPagePrintDto