Merge branch 'master' of http://120.76.84.145:10101/gitblit/r/java/Robotaxi
| | |
| | | |
| | | if (mqttPublishDto.getCode() == 200) { |
| | | if(!dto.getOrderId().contains("XU")){ |
| | | Map<String, Object> cancelContext = new HashMap<>(); |
| | | cancelContext.put("orderId", dto.getOrderId()); |
| | | cancelContext.put("vin", dto.getVin()); |
| | | cancelContext.put("cancelScene", StringUtils.isNotEmpty(dto.getCancelScene()) |
| | | ? dto.getCancelScene() |
| | | : CancelOrderSceneEnum.NORMAL_CANCEL.getCode()); |
| | | redisService.setCacheObject("CANCEL_ORDER_CONTEXT:" + taskId, |
| | | JSONObject.toJSONString(cancelContext), 30L, TimeUnit.MINUTES); |
| | | log.info("记录取消订单上下文成功,orderId: {}, vin: {}, taskId: {}, cancelScene: {}", |
| | | dto.getOrderId(), dto.getVin(), taskId, cancelContext.get("cancelScene")); |
| | | // 正常订单处理 |
| | | redisService.setCacheObject(String.valueOf(sequence), "cancelOrder_" + dto.getOrderId() + "_" + dto.getVin(), 30l, TimeUnit.MINUTES); |
| | | } |
| | | return R.ok(true); |
| | | } |
| | |
| | | @Slf4j |
| | | @Service |
| | | public class KafkaConsumerService { |
| | | private static final String CANCEL_ORDER_CONTEXT_PREFIX = "CANCEL_ORDER_CONTEXT:"; |
| | | private static final String REASSIGN_CANCEL_CONTEXT_PREFIX = "REASSIGN_CANCEL_CONTEXT:"; |
| | | |
| | | |
| | | @Resource |
| | |
| | | //已取消 |
| | | if(!orderId.contains("XU")){ |
| | | String taskId = orderStatusInfo.getTaskId(); |
| | | JSONObject cancelContext = getCancelOrderContext(taskId); |
| | | if (shouldSkipCancelForReassign(cancelContext)) { |
| | | JSONObject reassignCancelContext = resolveReassignCancelContext(orderId, orderStatusInfo); |
| | | if (Objects.nonNull(reassignCancelContext)) { |
| | | log.info("改派旧车取消回调,跳过订单取消处理,orderId: {}, taskId: {}, cancelScene: {}, context: {}", |
| | | orderId, taskId, cancelContext.getString("cancelScene"), cancelContext); |
| | | orderId, taskId, reassignCancelContext.getString("cancelScene"), reassignCancelContext); |
| | | //响应消息 |
| | | responseMessage(sequence, cancelContext.getString("vin")); |
| | | String responseVin = resolveReassignCancelResponseVin(reassignCancelContext); |
| | | if (StringUtils.isNotEmpty(responseVin)) { |
| | | responseMessage(sequence, responseVin); |
| | | } else { |
| | | log.warn("改派旧车取消回调未找到响应VIN,orderId: {}, taskId: {}, context: {}", |
| | | orderId, taskId, reassignCancelContext); |
| | | } |
| | | return; |
| | | } |
| | | if(orderId.contains("TEST")){ |
| | |
| | | //行程中取消订单,按照行程结束处理 |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.SEE_OFF_GUESTS, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.SEE_OFF_GUESTS.getCode()); |
| | | redisService.setCacheObject("ORDER_STATUS:" + orderId.substring(4), OrderStatusEnum.SEE_OFF_GUESTS.getCode(), 24L, TimeUnit.HOURS); |
| | | redisService.setCacheObject("ORDER_STATUS:" + orderId, OrderStatusEnum.SEE_OFF_GUESTS.getCode(), 24L, TimeUnit.HOURS); |
| | | }else{ |
| | | buildPushOrderStatus(orderId, OrderStatusEnum.CANCELED, sequence); |
| | | xpOrderClient.updateOrderStatus(Long.parseLong(orderId), OrderStatusEnum.CANCELED.getCode()); |
| | | redisService.setCacheObject("ORDER_STATUS:" + orderId.substring(4), OrderStatusEnum.CANCELED.getCode(), 24L, TimeUnit.HOURS); |
| | | redisService.setCacheObject("ORDER_STATUS:" + orderId, OrderStatusEnum.CANCELED.getCode(), 24L, TimeUnit.HOURS); |
| | | } |
| | | } |
| | | } |
| | |
| | | } |
| | | } |
| | | |
| | | /** |
| | | * 根据taskId获取订单取消的上下文信息 |
| | | * @param taskId |
| | | * @return |
| | | */ |
| | | private JSONObject getCancelOrderContext(String taskId) { |
| | | if (StringUtils.isEmpty(taskId)) { |
| | | private JSONObject getReassignCancelContext(String orderId) { |
| | | if (StringUtils.isEmpty(orderId)) { |
| | | return null; |
| | | } |
| | | Object cacheObject = redisService.getCacheObject(CANCEL_ORDER_CONTEXT_PREFIX + taskId); |
| | | Object cacheObject = redisService.getCacheObject(REASSIGN_CANCEL_CONTEXT_PREFIX + orderId); |
| | | if (cacheObject == null) { |
| | | return null; |
| | | } |
| | | return JSON.parseObject(cacheObject.toString()); |
| | | } |
| | | |
| | | /** |
| | | * 判断是否是改派旧车取消回调,是则跳过订单取消处理 |
| | | * @param cancelContext |
| | | * @return |
| | | */ |
| | | private boolean shouldSkipCancelForReassign(JSONObject cancelContext) { |
| | | if (cancelContext == null) { |
| | | return false; |
| | | private JSONObject resolveReassignCancelContext(String orderId, OrderStatusInfo orderStatusInfo) { |
| | | if (OrderStateChangeSource.ORDER_STATE_CHANGE_SOURCE_VEHICLE != orderStatusInfo.getChangeSource()) { |
| | | return null; |
| | | } |
| | | return CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE == CancelOrderSceneEnum.fromCode( |
| | | cancelContext.getString("cancelScene")); |
| | | JSONObject cancelContext = getReassignCancelContext(orderId); |
| | | if (cancelContext == null) { |
| | | return null; |
| | | } |
| | | if (CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE != CancelOrderSceneEnum.fromCode( |
| | | cancelContext.getString("cancelScene"))) { |
| | | return null; |
| | | } |
| | | R<XpOrder> orderResult = xpOrderClient.queryOrderById(Long.parseLong(orderId)); |
| | | XpOrder xpOrder = orderResult == null ? null : orderResult.getData(); |
| | | if (xpOrder == null) { |
| | | log.warn("改派取消回调识别失败,订单不存在,orderId: {}, context: {}", orderId, cancelContext); |
| | | return null; |
| | | } |
| | | Long newVehicleId = cancelContext.getLong("newVehicleId"); |
| | | Integer currentStatus = xpOrder.getStatus(); |
| | | boolean vehicleMatched = Objects.nonNull(newVehicleId) && Objects.equals(newVehicleId, xpOrder.getVehicleId()); |
| | | boolean statusMatched = Objects.nonNull(currentStatus) && currentStatus > 0 && currentStatus < 8; |
| | | if (vehicleMatched && statusMatched) { |
| | | return cancelContext; |
| | | } |
| | | log.info("改派取消回调未命中专用上下文,orderId: {}, currentVehicleId: {}, newVehicleId: {}, currentStatus: {}", |
| | | orderId, xpOrder.getVehicleId(), newVehicleId, currentStatus); |
| | | return null; |
| | | } |
| | | |
| | | private String resolveReassignCancelResponseVin(JSONObject cancelContext) { |
| | | if (cancelContext == null) { |
| | | return null; |
| | | } |
| | | String oldVehicleVin = cancelContext.getString("oldVehicleVin"); |
| | | if (StringUtils.isNotEmpty(oldVehicleVin)) { |
| | | return oldVehicleVin; |
| | | } |
| | | Long oldVehicleId = cancelContext.getLong("oldVehicleId"); |
| | | if (Objects.isNull(oldVehicleId)) { |
| | | return null; |
| | | } |
| | | R<XpVehicle> vehicleResult = xpVehicleClient.queryById(oldVehicleId); |
| | | XpVehicle xpVehicle = vehicleResult == null ? null : vehicleResult.getData(); |
| | | return xpVehicle == null ? null : xpVehicle.getVehicleVin(); |
| | | } |
| | | |
| | | /** |
| | |
| | | import com.xiaopeng.api.feignClient.automaticPilot.XPUClient; |
| | | import com.xiaopeng.api.vo.automaticPilot.MqttPublishVo; |
| | | import com.xiaopeng.api.vo.automaticPilot.protobuf.*; |
| | | import com.xiaopeng.common.core.exception.ServiceException; |
| | | import com.xiaopeng.common.core.utils.StringUtils; |
| | | import com.xiaopeng.common.core.utils.uuid.UUID; |
| | | import lombok.extern.slf4j.Slf4j; |
| | |
| | | log.info("getMqttPublishTopic vin,{},xpuIdMapping,{}", vin, JSON.toJSONString(xpuIdMapping)); |
| | | if (xpuIdMapping == null || StringUtils.isEmpty(xpuIdMapping.get(XPU_ID_TYPE)) ) { |
| | | log.error("根据vin查询车辆xpuid信息为空,vin={}", vin); |
| | | throw new RuntimeException("根据vin查询车辆xpuid信息为空"); |
| | | throw new ServiceException("根据vin查询车辆xpuid信息为空"); |
| | | } |
| | | return xpuIdMapping.get(XPU_ID_TYPE); |
| | | } |
| | |
| | | xpElectronicFenceAreaService.updateBatchById(electronicFenceAreaList); |
| | | }else{ |
| | | // 电子围栏失效 |
| | | XpElectronicFence electronicFence = xpElectronicFenceService.getById(electronicId); |
| | | electronicFence.setStatus(3); |
| | | xpElectronicFenceService.updateById(electronicFence); |
| | | List<XpElectronicFenceArea> electronicFenceAreaList = xpElectronicFenceAreaService.lambdaQuery().eq(XpElectronicFenceArea::getElectronicId, electronicId).list(); |
| | | // 设置为禁用 |
| | | for(XpElectronicFenceArea electronicFenceArea : electronicFenceAreaList){ |
| | | electronicFenceArea.setAreaStatus(2); |
| | | } |
| | | xpElectronicFenceAreaService.updateBatchById(electronicFenceAreaList); |
| | | xpElectronicFenceService.expireFence(electronicId); |
| | | } |
| | | |
| | | }catch(Exception e){ |
| New file |
| | |
| | | package com.xiaopeng.map.schedule; |
| | | |
| | | import com.xiaopeng.api.model.operation.XpElectronicFence; |
| | | import com.xiaopeng.map.service.XpElectronicFenceService; |
| | | import lombok.extern.slf4j.Slf4j; |
| | | import org.redisson.api.RLock; |
| | | import org.redisson.api.RedissonClient; |
| | | import org.springframework.scheduling.annotation.Scheduled; |
| | | import org.springframework.stereotype.Component; |
| | | |
| | | import javax.annotation.Resource; |
| | | import java.time.LocalDateTime; |
| | | import java.util.List; |
| | | import java.util.concurrent.TimeUnit; |
| | | import java.util.stream.Collectors; |
| | | |
| | | /** |
| | | * 电子围栏失效补偿定时任务 |
| | | */ |
| | | @Slf4j |
| | | @Component |
| | | public class ElectronicFenceFailureCompensationTask { |
| | | |
| | | private static final String LOCK_KEY = "MAP:ELECTRONIC_FENCE:FAILURE_COMPENSATE"; |
| | | private static final int LOCK_WAIT_SECONDS = 0; |
| | | private static final int LOCK_LEASE_SECONDS = 15; |
| | | |
| | | @Resource |
| | | private XpElectronicFenceService xpElectronicFenceService; |
| | | |
| | | @Resource |
| | | private RedissonClient redissonClient; |
| | | |
| | | @Scheduled(fixedDelay = 10 * 1000L) |
| | | public void compensateExpiredFence() { |
| | | RLock lock = redissonClient.getLock(LOCK_KEY); |
| | | boolean locked = false; |
| | | try { |
| | | locked = lock.tryLock(LOCK_WAIT_SECONDS, LOCK_LEASE_SECONDS, TimeUnit.SECONDS); |
| | | if (!locked) { |
| | | return; |
| | | } |
| | | |
| | | LocalDateTime now = LocalDateTime.now(); |
| | | List<XpElectronicFence> expiredFenceList = xpElectronicFenceService.lambdaQuery() |
| | | .eq(XpElectronicFence::getFailureType, 2) |
| | | .le(XpElectronicFence::getFailureTime, now) |
| | | .in(XpElectronicFence::getStatus, 1, 2) |
| | | .list(); |
| | | if (expiredFenceList == null || expiredFenceList.isEmpty()) { |
| | | return; |
| | | } |
| | | |
| | | List<Long> electronicIds = expiredFenceList.stream() |
| | | .map(XpElectronicFence::getId) |
| | | .collect(Collectors.toList()); |
| | | log.info("电子围栏失效补偿开始, count={}, ids={}", electronicIds.size(), electronicIds); |
| | | for (Long electronicId : electronicIds) { |
| | | try { |
| | | xpElectronicFenceService.expireFence(electronicId); |
| | | } catch (Exception e) { |
| | | log.error("电子围栏失效补偿单条处理异常, electronicId={}", electronicId, e); |
| | | } |
| | | } |
| | | log.info("电子围栏失效补偿完成, count={}, ids={}", electronicIds.size(), electronicIds); |
| | | } catch (InterruptedException e) { |
| | | Thread.currentThread().interrupt(); |
| | | log.warn("电子围栏失效补偿任务获取锁被中断", e); |
| | | } catch (Exception e) { |
| | | log.error("电子围栏失效补偿任务执行异常", e); |
| | | } finally { |
| | | try { |
| | | if (locked && lock.isHeldByCurrentThread()) { |
| | | lock.unlock(); |
| | | } |
| | | } catch (Exception e) { |
| | | log.warn("释放电子围栏失效补偿锁失败 lockKey={}", LOCK_KEY, e); |
| | | } |
| | | } |
| | | } |
| | | } |
| | |
| | | * @return |
| | | */ |
| | | List<XpElectronicFence> getList(); |
| | | |
| | | /** |
| | | * 将围栏置为已停用,并同步禁用围栏区域 |
| | | * @param electronicId 围栏ID |
| | | */ |
| | | void expireFence(Long electronicId); |
| | | } |
| | | |
| | | |
| | | |
| | | |
| | | |
| | |
| | | return list(); |
| | | } |
| | | |
| | | @Override |
| | | @Transactional |
| | | @ShardingSphereTransactionType(TransactionType.BASE) |
| | | public void expireFence(Long electronicId) { |
| | | if (electronicId == null) { |
| | | return; |
| | | } |
| | | XpElectronicFence electronicFence = this.getById(electronicId); |
| | | if (electronicFence == null || electronicFence.getStatus() == null) { |
| | | return; |
| | | } |
| | | Integer status = electronicFence.getStatus(); |
| | | if (status != 1 && status != 2) { |
| | | return; |
| | | } |
| | | electronicFence.setStatus(3); |
| | | this.updateById(electronicFence); |
| | | |
| | | List<XpElectronicFenceArea> electronicFenceAreaList = xpElectronicFenceAreaService.lambdaQuery() |
| | | .eq(XpElectronicFenceArea::getElectronicId, electronicId) |
| | | .list(); |
| | | if (CollUtil.isEmpty(electronicFenceAreaList)) { |
| | | return; |
| | | } |
| | | for (XpElectronicFenceArea electronicFenceArea : electronicFenceAreaList) { |
| | | electronicFenceArea.setAreaStatus(2); |
| | | } |
| | | xpElectronicFenceAreaService.updateBatchById(electronicFenceAreaList); |
| | | } |
| | | |
| | | |
| | | /** |
| | | * 计算围栏中心点 |
| | |
| | | |
| | | @ApiModelProperty(value = "起点") |
| | | @Excel(name = "起点", width = 30) |
| | | private String startAddress; |
| | | private String startPointName; |
| | | |
| | | @ApiModelProperty(value = "终点") |
| | | @Excel(name = "终点", width = 30) |
| | | private String endAddress; |
| | | private String endPointName; |
| | | |
| | | @ApiModelProperty(value = "选择车型") |
| | | @Excel(name = "选择车型", width = 15) |
| | |
| | | package com.xiaopeng.order.model.vo; |
| | | |
| | | import com.baomidou.mybatisplus.annotation.TableField; |
| | | import com.fasterxml.jackson.annotation.JsonFormat; |
| | | import io.swagger.annotations.ApiModel; |
| | | import io.swagger.annotations.ApiModelProperty; |
| | |
| | | private BigDecimal orderMoney; |
| | | @ApiModelProperty(value = "状态 0=已取消,1=待接单,2=待出发,3=接驾中,4=待客上车,5=乘客已上车,6=服务中,7=待客下车,8=待付款,9=待评价,10=已完成") |
| | | private Integer status; |
| | | |
| | | @ApiModelProperty(value = "下单站点名称") |
| | | private String startPointName; |
| | | |
| | | @ApiModelProperty(value = "下单终点站点名称") |
| | | private String endPointName; |
| | | } |
| | |
| | | @RequiredArgsConstructor(onConstructor_ = @Lazy) |
| | | public class XpOrderServiceImpl extends ServiceImpl<XpOrderMapper, XpOrder> implements IXpOrderService { |
| | | |
| | | private static final String REASSIGN_CANCEL_CONTEXT_PREFIX = "REASSIGN_CANCEL_CONTEXT:"; |
| | | private static final long REASSIGN_CANCEL_CONTEXT_TTL_MINUTES = 5L; |
| | | |
| | | private final UserResourcesClient userResourcesClient; |
| | | private final XpPointClient xpPointClient; |
| | | private final XpVehicleClient xpVehicleClient; |
| | |
| | | vo.setEndAddress(order.getEndAddress()); |
| | | vo.setOrderMoney(order.getOrderMoney()); |
| | | vo.setStatus(order.getStatus()); |
| | | vo.setStartPointName(order.getStartPointName()); |
| | | vo.setEndPointName(order.getEndPointName()); |
| | | |
| | | // 用户信息 |
| | | if (Objects.nonNull(order.getAppUserId()) && userInfoMap != null && userInfoMap.containsKey(order.getAppUserId().toString())) { |
| | |
| | | cancelDto.setOperation_type(OrderOperationType.CLOUD_CANCEL_ORDER); |
| | | cancelDto.setCancelScene(CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE.getCode()); |
| | | orderMissionClient.cancelOrder(cancelDto); |
| | | cacheReassignCancelContext(orderId, oldVehicleId, newVehicleId, |
| | | oldVehicle.getVehicleVin(), currentStatus); |
| | | log.info("已取消原车辆订单指令,订单ID: {}, VIN: {}, taskId: {}, cancelScene: {}", |
| | | orderId, oldVehicle.getVehicleVin(), cancelDto.getTaskId(), cancelDto.getCancelScene()); |
| | | |
| | |
| | | |
| | | } |
| | | |
| | | private void cacheReassignCancelContext(Long orderId, Long oldVehicleId, Long newVehicleId, |
| | | String oldVehicleVin, Integer preReassignStatus) { |
| | | JSONObject context = new JSONObject(); |
| | | context.put("orderId", orderId); |
| | | context.put("oldVehicleId", oldVehicleId); |
| | | context.put("newVehicleId", newVehicleId); |
| | | context.put("oldVehicleVin", oldVehicleVin); |
| | | context.put("cancelScene", CancelOrderSceneEnum.REASSIGN_OLD_VEHICLE.getCode()); |
| | | context.put("operationTime", System.currentTimeMillis()); |
| | | context.put("preReassignStatus", preReassignStatus); |
| | | redisService.setCacheObject(REASSIGN_CANCEL_CONTEXT_PREFIX + orderId, context.toJSONString(), |
| | | REASSIGN_CANCEL_CONTEXT_TTL_MINUTES, TimeUnit.MINUTES); |
| | | log.info("记录改派取消上下文成功,orderId: {}, oldVehicleId: {}, newVehicleId: {}, preReassignStatus: {}", |
| | | orderId, oldVehicleId, newVehicleId, preReassignStatus); |
| | | } |
| | | |
| | | /** |
| | | * 为原车辆创建返程巡游订单 |
| | | * <p> |