Browse Source

中山agv回调幂等性校验

master
常熟吴彦祖 3 weeks ago
parent
commit
b146e1e08b
  1. 57
      src/main/java/com/gaotao/modules/api/service/impl/AgvMessageServiceImpl.java
  2. 8
      src/main/java/com/gaotao/modules/automatedWarehouse/mapper/WcsIntegrationMapper.java
  3. 25
      src/main/resources/mapper/automatedWarehouse/WcsIntegrationMapper.xml

57
src/main/java/com/gaotao/modules/api/service/impl/AgvMessageServiceImpl.java

@ -43,6 +43,10 @@ import java.util.Map;
@Autowired
private PalletMapper palletMapper;
/**
* 老AGV接收仅在当前事务内条件新增一条在线明细;重复动作成功返回,不再生成新的等待询问。- rqrq
* 旧协议未传site,以全局唯一taskId对应运输主任务的site作为显式业务工厂,不申请写入锁。- rqrq
*/
@Override
@Transactional
public String agvTaskFeedback(AgvFeedbackData inData) {
@ -63,12 +67,17 @@ import java.util.Map;
log.info("接收AGV任务反馈:{}", requestJson);
// 2. 参数验证
if (inData == null || !StringUtils.hasText(inData.getTaskId())) {
throw new RuntimeException("参数验证失败:任务ID不能为空");
if (inData == null || !StringUtils.hasText(inData.getTaskId())
|| !StringUtils.hasText(inData.getTargetPoint())) {
throw new RuntimeException("参数验证失败:任务ID和目标点不能为空");
}
// 回调业务键和站点去除外围空格,避免同一任务或点位因空格被误判为新动作。- rqrq
String taskNo = inData.getTaskId().trim();
String targetPoint = inData.getTargetPoint().trim();
// 3. 根据taskId查询运输任务
WmsTransportTask transportTask = getTransportTaskById(inData.getTaskId());
// 按旧协议全局唯一taskId读取运输主任务,查不到或命中多条均不能继续落明细。- rqrq
WmsTransportTask transportTask = getTransportTaskById(taskNo);
if (transportTask == null) {
throw new RuntimeException("未找到对应的运输任务:" + inData.getTaskId());
}
@ -78,12 +87,15 @@ import java.util.Map;
if (!StringUtils.hasText(palletId)) {
throw new RuntimeException("运输任务中未找到栈板信息");
}
WmsTransportTask checkTask= wcsIntegrationMapper.getTransportTaskByTaskNo(inData.getTaskId());
if(checkTask==null){
throw new RuntimeException("运输任务不存在");
// 旧AGV请求不含site,使用已校验主任务工厂并显式传入写入条件,避免固定55导致串厂。- rqrq
if (!StringUtils.hasText(transportTask.getSite())) {
throw new RuntimeException("运输任务缺少工厂编码:" + taskNo);
}
String site = transportTask.getSite().trim();
WmsTransportTask checkTask = transportTask;
String statusDesc="";
if(inData.getTargetPoint().equals(checkTask.getToLocation())){
if(targetPoint.equals(checkTask.getToLocation())){
//业务逻辑转移到定时任务
// // 5. 更新栈板calling_flag为N
// String username = "AGV_SYSTEM";
@ -105,21 +117,35 @@ import java.util.Map;
// updatePalletLocationOnly(transportTask, username);
// }
statusDesc="送货完成";
}else if(inData.getTargetPoint().equals(checkTask.getFromLocation())){
}else if(targetPoint.equals(checkTask.getFromLocation())){
statusDesc="取货完成";
}else {
statusDesc="等待询问";
}
WmsTransportTaskDetail detail = new WmsTransportTaskDetail();
detail.setSite("55");
detail.setTaskNo(inData.getTaskId());
detail.setSite(site);
detail.setTaskNo(taskNo);
detail.setItemNo(1);
detail.setSeqNo(wcsIntegrationMapper.getMaxSeqNoForTaskDetail("55",inData.getTaskId()));
detail.setActionType(statusDesc);
detail.setToLocation(inData.getTargetPoint());
detail.setToLocation(targetPoint);
detail.setStatus("已录入");
detail.setAgvName(inData.getDeviceId());
wcsIntegrationMapper.insertWmsTransportTaskDetail(detail);
// 同site+taskNo+动作在在线表已有任何状态时返回0;SQL内分配序号,不获取写入锁。- rqrq
int insertedRows = wcsIntegrationMapper.insertAgvFeedbackTaskDetailIfAbsent(detail);
if (insertedRows == 0) {
String duplicateMessage = "在线明细已存在,跳过重复AGV回调,site=" + site
+ ",taskNo=" + taskNo + ",actionType=" + statusDesc;
log.info("{} - rqrq", duplicateMessage);
if (logId != null) {
// 重复回调仍按原协议记成功日志并返回SUCCESS,不覆盖首次明细及其处理状态。- rqrq
interfaceCallLogService.updateCallResult(logId, duplicateMessage, "SUCCESS", null, null);
}
return "SUCCESS";
}
if (insertedRows != 1) {
throw new RuntimeException("AGV回调明细写入行数异常:" + insertedRows);
}
// 8. 更新接口日志为成功
if (logId != null) {
@ -141,9 +167,10 @@ import java.util.Map;
}
/**
* 根据taskId(实际是taskNo)查询运输任务
* 根据旧协议全局唯一taskId(实际是taskNo)查询运输任务,结果site用于后续显式隔离。- rqrq
*/
private WmsTransportTask getTransportTaskById(String taskId) {
// 复用原在线主任务查询;多条匹配由Mapper拒绝,不任取某个工厂继续处理。- rqrq
return wcsIntegrationMapper.getTransportTaskByTaskNo(taskId);
}

8
src/main/java/com/gaotao/modules/automatedWarehouse/mapper/WcsIntegrationMapper.java

@ -467,6 +467,14 @@ public interface WcsIntegrationMapper {
void batchUpdateCompletedTaskStatus(@Param("site") String site, @Param("taskKeys") List<TaskDetailKey> taskKeys);
void insertWmsTransportTaskDetail(WmsTransportTaskDetail inData);
/**
* 老AGV回调仅按site+taskNo+actionType判断在线明细是否存在,任意状态均跳过重复插入。- rqrq
* site取已校验运输主任务;序号在SQL内按同site+taskNo+itemNo递增,不读取历史表或申请写入锁。- rqrq
* 返回1表示新增、0表示已存在;异常交调用方返回失败,供AGV按原协议重试。- rqrq
*/
int insertAgvFeedbackTaskDetailIfAbsent(WmsTransportTaskDetail inData);
void insertWmsOrderTaskDetail(WmsOrderTaskDetail inData);
Integer getMaxSeqNoForTaskDetail(@Param("site") String site, @Param("taskNo") String taskNo);

25
src/main/resources/mapper/automatedWarehouse/WcsIntegrationMapper.xml

@ -944,6 +944,31 @@
)
</insert>
<!-- 老AGV接收幂等:只看在线表site+taskNo+actionType,任意状态已有明细就返回0,不覆盖首次记录。- rqrq -->
<!-- 普通已提交读取,不申请应用锁、不加更新锁或范围锁提示;极少数完全并发请求仍可能同时通过存在性判断。- rqrq -->
<insert id="insertAgvFeedbackTaskDetailIfAbsent"
parameterType="com.gaotao.modules.automatedWarehouse.entity.WmsTransportTaskDetail">
INSERT INTO wms_transport_task_detail (
site, task_no, item_no, seq_no, action_type, [comment],
from_location, to_location, agv_code, [status], start_time,
error_code, error_msg, agv_name
)
SELECT
#{site}, #{taskNo}, #{itemNo},
(SELECT ISNULL(MAX(d.seq_no), 0) + 1
FROM wms_transport_task_detail d
WHERE d.site = #{site} AND d.task_no = #{taskNo} AND d.item_no = #{itemNo}),
#{actionType}, #{comment}, #{fromLocation}, #{toLocation}, #{agvCode},
#{status}, #{startTime}, #{errorCode}, #{errorMsg}, #{agvName}
WHERE NOT EXISTS (
SELECT 1
FROM wms_transport_task_detail existing_detail
WHERE existing_detail.site = #{site}
AND existing_detail.task_no = #{taskNo}
AND existing_detail.action_type = #{actionType}
)
</insert>
<insert id="insertWmsOrderTaskDetail" >
insert into wms_order_task_detail(
site,task_no,item_no,seq_no,action_type,[comment],from_location,to_location,agv_code,[status],start_time,

Loading…
Cancel
Save