RetryRobotTaskCommandHandler.cs
5.6 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
using MassTransit;
using Microsoft.Extensions.Logging;
using Rcs.Application.Common;
using Rcs.Application.MessageBus.Commands;
using Rcs.Application.Services.Protocol;
using Rcs.Domain.Entities;
using Rcs.Domain.Extensions;
using Rcs.Domain.Repositories;
using TaskStatus = Rcs.Domain.Entities.TaskStatus;
namespace Rcs.Infrastructure.MessageBus.Handlers.Commands;
/// <summary>
/// 重新执行任务命令处理器
/// 语义:恢复当前任务为已分配,并将其子任务恢复为执行中
/// </summary>
public class RetryRobotTaskCommandHandler : IConsumer<RetryRobotTaskCommand>
{
private readonly ILogger<RetryRobotTaskCommandHandler> _logger;
private readonly IRobotTaskRepository _robotTaskRepository;
private readonly IRobotRepository _robotRepository;
private readonly IProtocolServiceFactory _protocolServiceFactory;
public RetryRobotTaskCommandHandler(
ILogger<RetryRobotTaskCommandHandler> logger,
IRobotTaskRepository robotTaskRepository,
IRobotRepository robotRepository,
IProtocolServiceFactory protocolServiceFactory)
{
_logger = logger;
_robotTaskRepository = robotTaskRepository;
_robotRepository = robotRepository;
_protocolServiceFactory = protocolServiceFactory;
}
public async Task Consume(ConsumeContext<RetryRobotTaskCommand> context)
{
var command = context.Message;
try
{
var task = await _robotTaskRepository.GetByIdWithDetailsAsync(command.TaskId, context.CancellationToken);
if (task == null)
{
await context.RespondAsync(ApiResponse.Failed($"未找到任务ID为 {command.TaskId} 的任务"));
return;
}
if (!task.RobotId.HasValue || task.RobotId.Value == Guid.Empty)
{
throw new BusinessException($"任务 {task.TaskCode} 未分配机器人,无法重试恢复");
}
var robot = task.Robot
?? await _robotRepository.GetByIdFullDataAsync(task.RobotId.Value, context.CancellationToken);
if (robot == null)
{
throw new BusinessException($"任务 {task.TaskCode} 对应机器人不存在: {task.RobotId}");
}
var skipCancelForInboundTask = ShouldSkipCacheReleaseForInboundTask(task);
if (skipCancelForInboundTask)
{
_logger.LogInformation(
"[任务重试] 入库任务跳过清缓存释放: TaskCode={TaskCode}, TaskId={TaskId}, TaskName={TaskName}, Source={Source}, TemplateCode={TemplateCode}, TemplateName={TemplateName}",
task.TaskCode,
task.TaskId,
task.TaskName,
task.Source,
task.TaskTemplate?.TemplateCode,
task.TaskTemplate?.TemplateName);
}
else
{
// 先按机器人协议取消当前机器人任务,确保机器人端无旧任务缓存
var protocolService = _protocolServiceFactory.GetService(robot);
await protocolService.CancelRobotTasksAsync(robot, context.CancellationToken);
}
// 恢复主任务(不更新时间)
task.RobotId = robot.RobotId;
task.Status = TaskStatus.Assigned;
task.Pause = false;
task.ErrorInfo = null;
// 恢复子任务为等待中(不更新时间)
foreach (var subTask in task.SubTasks)
{
subTask.RobotId = robot.RobotId;
subTask.Status = TaskStatus.Pending;
}
await _robotTaskRepository.UpdateAsync(task, context.CancellationToken);
await _robotTaskRepository.SaveChangesAsync(context.CancellationToken);
await context.RespondAsync(ApiResponse.Successful("重新执行成功"));
}
catch (Exception ex)
{
_logger.LogError(ex, "重新执行任务失败, TaskId: {TaskId}", command.TaskId);
await context.RespondAsync(ApiResponse.Failed(ex.Message));
}
}
private static bool ShouldSkipCacheReleaseForInboundTask(RobotTask? task)
{
if (task == null)
{
return false;
}
var taskName = task.TaskName?.Trim();
var taskCode = task.TaskCode?.Trim();
var source = task.Source?.Trim();
var templateCode = task.TaskTemplate?.TemplateCode?.Trim();
var templateName = task.TaskTemplate?.TemplateName?.Trim();
if (string.Equals(source, "WMS", StringComparison.OrdinalIgnoreCase)
&& !string.IsNullOrWhiteSpace(taskName)
&& taskName.StartsWith("WMS_", StringComparison.OrdinalIgnoreCase))
{
var suffix = taskName.Substring(4);
if (int.TryParse(suffix, out var taskType))
{
return taskType == 1;
}
}
var matchTargets = new[]
{
taskName,
taskCode,
source,
templateCode,
templateName
};
if (matchTargets.All(string.IsNullOrWhiteSpace))
{
return false;
}
var inboundKeywords = new[]
{
"入库",
"上架",
"INBOUND",
"PUTAWAY",
"PUT_AWAY",
"STORAGE_IN",
"STORE_IN"
};
return matchTargets
.Where(v => !string.IsNullOrWhiteSpace(v))
.Any(v => inboundKeywords.Any(k => v!.Contains(k, StringComparison.OrdinalIgnoreCase)));
}
}