SubTaskCompletedDomainEventHandler.cs
6.08 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
using Microsoft.Extensions.Logging;
using Rcs.Application.Services;
using Rcs.Application.Services.Protocol;
using Rcs.Domain.Entities;
using Rcs.Domain.Entities.DomainEvents.RobotSubTask;
using Rcs.Domain.Repositories;
using TaskStatus = Rcs.Domain.Entities.TaskStatus;
namespace Rcs.Infrastructure.MessageBus.Handlers.Events.RobotSubTask;
/// <summary>
/// 子任务完成领域事件处理器
/// 负责:清理VDA路径缓存、清空机器人缓存Path、判断是否所有子任务完成、级联触发父任务完成、释放交通管制锁
/// @author zzy
/// </summary>
public class SubTaskCompletedDomainEventHandler
{
private readonly ILogger<SubTaskCompletedDomainEventHandler> _logger;
private readonly IRobotTaskRepository _taskRepository;
private readonly IRobotRepository _robotRepository;
private readonly IRobotCacheService _robotCacheService;
private readonly IUnifiedTrafficControlService _trafficControlService;
private readonly IProtocolServiceFactory _protocolServiceFactory;
public SubTaskCompletedDomainEventHandler(
ILogger<SubTaskCompletedDomainEventHandler> logger,
IRobotTaskRepository taskRepository,
IRobotRepository robotRepository,
IRobotCacheService robotCacheService,
IUnifiedTrafficControlService trafficControlService,
IProtocolServiceFactory protocolServiceFactory)
{
_logger = logger;
_taskRepository = taskRepository;
_robotRepository = robotRepository;
_robotCacheService = robotCacheService;
_trafficControlService = trafficControlService;
_protocolServiceFactory = protocolServiceFactory;
}
/// <summary>
/// 处理子任务完成事件
/// 1. 清理该子任务的VDA路径缓存
/// 2. 清空机器人Redis缓存中的Path字段
/// 3. 判断所有子任务是否完成
/// 4. 全部完成时:释放交通管制锁 → 触发父任务完成
/// @author zzy
/// </summary>
public async System.Threading.Tasks.Task Handle(SubTaskCompletedDomainEvent domainEvent)
{
_logger.LogInformation(
"[子任务完成] SubTaskId={SubTaskId}, TaskId={TaskId}, RobotId={RobotId}",
domainEvent.SubTaskId, domainEvent.TaskId, domainEvent.RobotId);
// 1. 清理该子任务的VDA路径缓存(通过协议服务清理)
try
{
if (domainEvent.RobotId != Guid.Empty)
{
var robot = await _robotRepository.GetByIdAsync(domainEvent.RobotId);
if (robot != null)
{
var protocolService = _protocolServiceFactory.GetService(robot);
await protocolService.ClearAllVdaPathCacheAsync(domainEvent.RobotId);
}
else
{
_logger.LogWarning("[子任务完成] 清理VDA路径缓存失败,机器人不存在: RobotId={RobotId}", domainEvent.RobotId);
}
}
}
catch (Exception ex)
{
_logger.LogError(ex, "[子任务完成] 清理VDA路径缓存异常: RobotId={RobotId}, SubTaskId={SubTaskId}",
domainEvent.RobotId, domainEvent.SubTaskId);
}
// 2. 清空机器人Redis缓存中的Path字段
await ClearRobotCachePathAsync(domainEvent.RobotId);
// 3. 释放该机器人的所有交通管制锁
if (domainEvent.RobotId != Guid.Empty)
{
var releasedCount = await _trafficControlService.ReleaseAllRobotLocksAsync(domainEvent.RobotId);
}
// 4. 获取父任务及所有子任务
var task = await _taskRepository.GetByIdWithDetailsAsync(domainEvent.TaskId);
if (task == null)
{
_logger.LogWarning("[子任务完成] 父任务不存在: TaskId={TaskId}", domainEvent.TaskId);
return;
}
// 幂等保护:父任务已完成则跳过
if (task.Status == TaskStatus.Completed)
{
_logger.LogDebug("[子任务完成] 父任务已完成,跳过: TaskId={TaskId}", domainEvent.TaskId);
return;
}
// 5. 判断是否所有子任务都已完成
var allSubTasksCompleted = task.SubTasks.All(st => st.Status == TaskStatus.Completed);
if (allSubTasksCompleted)
{
_logger.LogInformation(
"[子任务完成] 所有子任务已完成,触发父任务完成: TaskId={TaskId}, TaskCode={TaskCode}",
task.TaskId, task.TaskCode);
// 6. 触发父任务完成(会触发 TaskCompletedDomainEvent -> 更新库位状态)
task.Completed(domainEvent.RobotId);
await _taskRepository.UpdateAsync(task);
await _taskRepository.SaveChangesAsync();
}
else
{
_logger.LogInformation(
"[子任务完成] 还有未完成的子任务: TaskId={TaskId}, 已完成={Completed}/{Total}",
task.TaskId,
task.SubTasks.Count(st => st.Status == TaskStatus.Completed),
task.SubTasks.Count);
}
}
/// <summary>
/// 清空机器人Redis缓存中的Path字段
/// 子任务完成后机器人不再沿该路径行驶,需清空Path以避免前端显示过期路径
/// @author zzy
/// </summary>
/// <param name="robotId">机器人ID</param>
private async System.Threading.Tasks.Task ClearRobotCachePathAsync(Guid robotId)
{
try
{
if (robotId == Guid.Empty) return;
var robot = await _robotRepository.GetByIdAsync(robotId);
if (robot == null)
{
_logger.LogWarning("[子任务完成] 清空缓存Path失败,机器人不存在: RobotId={RobotId}", robotId);
return;
}
var result = await _robotCacheService.SetLocationValueAsync(
robot.RobotManufacturer, robot.RobotSerialNumber, "Path", "");
}
catch (Exception ex)
{
_logger.LogError(ex, "[子任务完成] 清空机器人缓存Path异常: RobotId={RobotId}", robotId);
}
}
}