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:
@ -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
|
||||
|
||||
Reference in New Issue
Block a user