admin/src/Oms.Application/Services/Orders/OrderService.BatchJob.cs
zzh 4f3bbd17bc feat(order): 订单批量任务 RabbitMQ 异步处理与治理 API
引入批量 Job 表、RabbitMQ 队列与消费者,支持导入/小包创建及我的订单批量操作异步化,并提供任务列表、重试失败、取消 pending 与 DLX 监控接口及测试。

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-07-08 09:52:22 +08:00

163 lines
6.3 KiB
C#

using Fake.Application;
using Fake.Security.Claims;
using Microsoft.AspNetCore.Mvc;
using Oms.Application.Dtos.Orders;
using Oms.Application.Dtos.Shared;
using Oms.Application.Services.Orders.Batch;
using Oms.Application.Messaging;
using Oms.Application.Shared;
using Oms.Domain.CustomersAggregate.Repositories;
using Oms.Domain.OrdersAggregate.Consts;
namespace Oms.Application.Services.Orders;
public partial class OrderService
{
private OrderBatchJobCoordinator BatchJobCoordinator =>
LazyServiceProvider.GetRequiredService<OrderBatchJobCoordinator>();
/// <summary>
/// 创建订单批量异步任务并入队 RabbitMQ。
/// </summary>
[HttpPost("/order/batch/jobs")]
public Task<OrderBatchJobOutput> CreateBatchJobAsync([FromBody] OrderBatchJobCreateInput input)
{
return BatchJobCoordinator.CreateAndEnqueueAsync(input, CurrentUser.GetId<int>());
}
/// <summary>
/// 查询批量任务进度。
/// </summary>
[HttpGet("/order/batch/jobs/{id:int}")]
public async Task<OrderBatchJobOutput> GetBatchJobAsync([FromRoute] int id)
{
var job = await BatchJobCoordinator.GetJobAsync(id);
if (job == null)
{
throw new BusinessException("批量任务不存在");
}
return job;
}
/// <summary>
/// 分页查询批量任务列表。
/// </summary>
[HttpGet("/order/batch/jobs")]
public async Task<OmsPageResult<OrderBatchJobOutput>> GetBatchJobListAsync([FromQuery] OrderBatchJobListInput input)
{
var customerId = await OmsSessionHelper.ResolveListCustomerIdAsync(
LazyServiceProvider.GetRequiredService<ICustomerRepository>(),
CurrentUser,
null);
return await BatchJobCoordinator.GetJobListAsync(input, customerId);
}
/// <summary>
/// 查询批量任务子项明细。
/// </summary>
[HttpGet("/order/batch/jobs/{id:int}/items")]
public async Task<List<OrderBatchJobItemOutput>> GetBatchJobItemsAsync([FromRoute] int id)
{
var job = await BatchJobCoordinator.GetJobAsync(id);
if (job == null)
{
throw new BusinessException("批量任务不存在");
}
return await BatchJobCoordinator.GetJobItemsAsync(id);
}
/// <summary>
/// 异步批量创建轨迹订单(替代前端逐条调用)。
/// </summary>
[HttpPost("/order/batch/track-upsert")]
public Task<OrderBatchJobOutput> BatchTrackUpsertAsync([FromBody] OrderBatchJobCreateInput input)
{
input.Action = OrderBatchActionCodes.TrackUpsertSmallBag;
return BatchJobCoordinator.CreateAndEnqueueAsync(input, CurrentUser.GetId<int>());
}
/// <summary>
/// 异步批量预报下游订单。
/// </summary>
[HttpPost("/order/batch/downstream-forward")]
public Task<OrderBatchJobOutput> BatchDownstreamForwardAsync([FromBody] OrderBatchJobCreateInput input)
{
input.Action = OrderBatchActionCodes.DownstreamForwardCreateOne;
return BatchJobCoordinator.CreateAndEnqueueAsync(input, CurrentUser.GetId<int>());
}
private Task<OrderBatchJobOutput> EnqueueOrderBatchAsync(string action, OrderBatchJobCreateInput input)
{
input.Action = action;
return BatchJobCoordinator.CreateAndEnqueueAsync(input, CurrentUser.GetId<int>());
}
[HttpPost("/order/batch/pay")]
public Task<OrderBatchJobOutput> BatchPayAsync([FromBody] OrderBatchJobCreateInput input) =>
EnqueueOrderBatchAsync(OrderBatchActionCodes.Pay, input);
[HttpPost("/order/batch/pre-declare")]
public Task<OrderBatchJobOutput> BatchPreDeclareAsync([FromBody] OrderBatchJobCreateInput input) =>
EnqueueOrderBatchAsync(OrderBatchActionCodes.PreDeclare, input);
[HttpPost("/order/batch/intercept")]
public Task<OrderBatchJobOutput> BatchInterceptAsync([FromBody] OrderBatchJobCreateInput input) =>
EnqueueOrderBatchAsync(OrderBatchActionCodes.Intercept, input);
[HttpPost("/order/batch/cancel-intercept")]
public Task<OrderBatchJobOutput> BatchCancelInterceptAsync([FromBody] OrderBatchJobCreateInput input) =>
EnqueueOrderBatchAsync(OrderBatchActionCodes.CancelIntercept, input);
[HttpPost("/order/batch/delete")]
public Task<OrderBatchJobOutput> BatchDeleteAsync([FromBody] OrderBatchJobCreateInput input) =>
EnqueueOrderBatchAsync(OrderBatchActionCodes.Delete, input);
[HttpPost("/order/batch/print")]
public Task<OrderBatchJobOutput> BatchPrintAsync([FromBody] OrderBatchJobCreateInput input) =>
EnqueueOrderBatchAsync(OrderBatchActionCodes.Print, input);
[HttpPost("/order/batch/mark-problematic")]
public Task<OrderBatchJobOutput> BatchMarkProblematicAsync([FromBody] OrderBatchJobCreateInput input) =>
EnqueueOrderBatchAsync(OrderBatchActionCodes.MarkProblematic, input);
[HttpPost("/order/batch/mark-claimed")]
public Task<OrderBatchJobOutput> BatchMarkClaimedAsync([FromBody] OrderBatchJobCreateInput input) =>
EnqueueOrderBatchAsync(OrderBatchActionCodes.MarkClaimed, input);
[HttpPost("/order/batch/handle-status-update")]
public Task<OrderBatchJobOutput> BatchHandleStatusUpdateAsync([FromBody] OrderBatchJobCreateInput input) =>
EnqueueOrderBatchAsync(OrderBatchActionCodes.HandleStatusUpdate, input);
/// <summary>
/// 查询 RabbitMQ 队列与 DLX 堆积情况。
/// </summary>
[HttpGet("/order/batch/dlx/stats")]
public Task<OrderBatchDlxStatsOutput> GetBatchDlxStatsAsync()
{
var inspector = LazyServiceProvider.GetRequiredService<IOrderBatchQueueInspector>();
return inspector.GetStatsAsync();
}
/// <summary>
/// 重新投递失败子项。
/// </summary>
[HttpPost("/order/batch/jobs/{id:int}/retry-failed")]
public Task<OrderBatchJobManageOutput> RetryFailedBatchJobAsync(
[FromRoute] int id,
[FromBody] OrderBatchJobRetryFailedInput? input)
{
return BatchJobCoordinator.RetryFailedAsync(id, input, CurrentUser.GetId<int>());
}
/// <summary>
/// 取消尚未执行的 pending 子项。
/// </summary>
[HttpPost("/order/batch/jobs/{id:int}/cancel")]
public Task<OrderBatchJobManageOutput> CancelBatchJobAsync([FromRoute] int id)
{
return BatchJobCoordinator.CancelPendingAsync(id, CurrentUser.GetId<int>());
}
}