新增排单锁

This commit is contained in:
gaoqr
2026-06-08 19:05:10 +08:00
parent 033f993668
commit 7046d9d368
9 changed files with 124 additions and 7 deletions
@@ -27,4 +27,9 @@ public class RedisKeyConstants {
* 字典数据i18n缓存刷新
*/
public static final String DICT_DATA_I18N_CACHE_REFRESH = "DICT_DATA_I18N_CACHE_REFRESH";
/**
* 排单优化锁
*/
public static final String ORDER_PLAN_OPTIMIZE_KEY = "order_plan_optimize:%s";
}
@@ -24,6 +24,7 @@ public class ErrorCodeConstants {
public static final ErrorCode ORDER_PLATE_UPDATE_CONCURRENCY_ERROR = new ErrorCode(1_003_107_012, "order.plate.update.concurrency.error");
public static final ErrorCode GOODS_PLATE_UPDATE_CONCURRENCY_ERROR = new ErrorCode(1_003_107_013, "goods.plate.update.concurrency.error");
public static final ErrorCode BODY_PLATE_UPDATE_CONCURRENCY_ERROR = new ErrorCode(1_003_107_014, "body.plate.update.concurrency.error");
public static final ErrorCode ORDER_PLAN_LOCKED = new ErrorCode(1_003_107_015, "当前排单已锁定,请稍后再试");
// ========== 订单商品 1_003_108_000 ==========
@@ -72,9 +72,9 @@ public class OptimizePlanController {
@PreAuthorize("@ss.hasAnyPermissions('placeorder:optimize','production:manager-list:calculate','manage:order-plan:process-scheme','producePlan:order-plan:process-scheme','producePlan:optimize')")
public CommonResult<OrderSource> getOrderSource(@Schema(description = "订单id") @RequestParam(required = false) Long orderId,
@Schema(description = "排单id") @RequestParam(required = false) Long planId,
@Schema(description = "机台Id") @RequestParam(required = false) Long machineId
@Schema(description = "排单值") @RequestParam(required = false) String val
) {
return CommonResult.success(optimizePlanService.getOrderSource(orderId, planId, machineId));
return CommonResult.success(optimizePlanService.getOrderSource(orderId, planId, val));
}
@@ -193,6 +193,19 @@ public class PlanController {
}
@PostMapping("/lock")
@Operation(summary = "获取排单锁")
@PreAuthorize("@ss.hasAnyPermissions('placeorder:optimize','production:manager-list:calculate','manage:order-plan:process-scheme','producePlan:order-plan:process-scheme','producePlan:optimize')")
public CommonResult<Boolean> getPlanLock(@RequestBody OrderPlanLockReqVO orderPlanLockReqVO) {
planService.getPlanLock(orderPlanLockReqVO);
return success(true);
}
@PostMapping("/release/lock")
@Operation(summary = "释放排单锁")
@PreAuthorize("@ss.hasAnyPermissions('placeorder:optimize','production:manager-list:calculate','manage:order-plan:process-scheme','producePlan:order-plan:process-scheme','producePlan:optimize')")
public CommonResult<Boolean> releasePlanLock(@RequestBody OrderPlanLockReqVO orderPlanLockReqVO) {
planService.releasePlanLock(orderPlanLockReqVO);
return success(true);
}
}
@@ -0,0 +1,23 @@
package com.cf.imes.module.executor.controller.admin.plan.vo;
import io.swagger.v3.oas.annotations.media.Schema;
import jakarta.validation.constraints.NotNull;
import lombok.Data;
/**
*
*
* @author Gqr
* @since 2026/6/8 16:43
*/
@Data
@Schema(description = "排单锁定请求参数")
public class OrderPlanLockReqVO {
@Schema(description = "排单ID")
@NotNull(message = "排单ID不能为空")
private Long planId;
@Schema(description = "排单优化本地值")
@NotNull(message = "排单优化本地值不能为空")
private String val;
}
@@ -27,7 +27,7 @@ public interface OptimizePlanService {
Map<String, Object> getLabelDataSourceValue(GetSourceDataReq req);
OrderSource getOrderSource(Long orderId, Long planId, Long machineId);
OrderSource getOrderSource(Long orderId, Long planId, String val);
OrderSource getOrderSourceByOrderId(Long orderId);
@@ -71,6 +71,7 @@ import com.cf.imes.module.executor.dal.mysql.plate.PlateMapper;
import com.cf.imes.module.executor.dal.mysql.remainplaten.RemainPlateMapper;
import com.cf.imes.module.executor.enums.ErrorCodeConstants;
import com.cf.imes.module.executor.enums.plan.FlowProcessStatus;
import com.cf.imes.module.executor.service.plan.PlanService;
import com.cf.imes.module.executor.util.elasticsearch.EsUtils;
import com.cf.imes.module.system.api.dataSource.DataSourceApi;
import com.cf.imes.module.system.api.machine.MachineApi;
@@ -160,6 +161,9 @@ public class OptimizePlanServiceImpl implements OptimizePlanService {
@Resource
private PlateGoodMapper plateGoodMapper;
@Resource
private PlanService planService;
@Value("${chenfeng.plan.create.plate-threshold:20000}")
private int planCreatePlateThreshold;
@@ -282,7 +286,7 @@ public class OptimizePlanServiceImpl implements OptimizePlanService {
}
@Override
public OrderSource getOrderSource(Long orderId, Long planId, Long machineId) {
public OrderSource getOrderSource(Long orderId, Long planId, String val) {
if (!Objects.isNull(orderId) && !Objects.isNull(planId)) {
throw new ServiceException(ORDER_PLAN_ID_IS_ONE);
}
@@ -292,6 +296,8 @@ public class OptimizePlanServiceImpl implements OptimizePlanService {
return orderSource;
}
if (ObjectUtil.isNotNull(planId)) {
// 获取排单锁
planService.getPlanLock(new OrderPlanLockReqVO().setPlanId(planId).setVal(val));
orderSource = getOrderSourceByPlanId(planId);
return orderSource;
}
@@ -2,6 +2,7 @@ package com.cf.imes.module.executor.service.plan;
import com.cf.imes.framework.common.pojo.PageResult;
import com.cf.imes.module.executor.controller.admin.order.vo.order.OrderRespVO;
import com.cf.imes.module.executor.controller.admin.plan.vo.OrderPlanLockReqVO;
import com.cf.imes.module.executor.controller.admin.plan.bo.OrderRoomBodyList;
import com.cf.imes.module.executor.controller.admin.plan.vo.*;
@@ -93,4 +94,17 @@ public interface PlanService {
List<PlateResList> getPlanPlateList(Long planId);
/**
* 获取排单锁
*
* @param orderPlanLockReqVO
*/
void getPlanLock(OrderPlanLockReqVO orderPlanLockReqVO);
/**
* 释放排单锁
*
* @param orderPlanLockReqVO
*/
void releasePlanLock(OrderPlanLockReqVO orderPlanLockReqVO);
}
@@ -4,6 +4,7 @@ import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import co.elastic.clients.elasticsearch.ElasticsearchClient;
import co.elastic.clients.elasticsearch._types.FieldValue;
import co.elastic.clients.elasticsearch.core.UpdateByQueryRequest;
@@ -27,6 +28,7 @@ import com.cf.imes.framework.security.core.util.SecurityFrameworkUtils;
import com.cf.imes.module.executor.controller.admin.goods.vo.GoodsRespVO;
import com.cf.imes.module.executor.controller.admin.order.vo.order.OrderPlanPlateNumAndAreaRespVO;
import com.cf.imes.module.executor.controller.admin.order.vo.order.OrderRespVO;
import com.cf.imes.module.executor.controller.admin.plan.vo.OrderPlanLockReqVO;
import com.cf.imes.module.executor.controller.admin.plan.bo.OrderRoomBodyList;
import com.cf.imes.module.executor.controller.admin.plan.saveOptimize.RemainBoardInfo;
import com.cf.imes.module.executor.controller.admin.plan.vo.*;
@@ -59,11 +61,11 @@ import com.cf.imes.module.executor.dal.mysql.remainplaten.RemainPlateMapper;
import com.cf.imes.module.executor.enums.ErrorCodeConstants;
import com.cf.imes.module.executor.enums.OrderPlanQueryTypeEnum;
import com.cf.imes.module.executor.enums.OrderStatusEnum;
import com.cf.imes.module.executor.service.order.OrderService;
import com.cf.imes.module.executor.util.elasticsearch.EsUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.aop.framework.AopContext;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.ObjectUtils;
@@ -71,13 +73,16 @@ import org.springframework.validation.annotation.Validated;
import jakarta.annotation.Resource;
import java.math.BigDecimal;
import java.time.Duration;
import java.time.LocalDateTime;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;
import static com.cf.imes.framework.common.exception.enums.GlobalErrorCodeConstants.DATA_DATA_ERROR;
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.framework.common.util.json.JsonUtils.parseArray;
import static com.cf.imes.framework.redis.constants.RedisKeyConstants.ORDER_PLAN_OPTIMIZE_KEY;
import static com.cf.imes.framework.security.core.util.SecurityFrameworkUtils.getUserOrganId;
import static com.cf.imes.module.executor.enums.ErrorCodeConstants.*;
import static com.cf.imes.module.executor.enums.EsIndexEnum.*;
@@ -135,7 +140,7 @@ public class PlanServiceImpl implements PlanService {
private OrderComponentMapper orderComponentMapper;
@Resource
private OrderService orderService;
private StringRedisTemplate stringRedisTemplate;
// 重复使用的常量
private static final String FIELD_ORDER_ID = "o.id";
@@ -2087,4 +2092,54 @@ public class PlanServiceImpl implements PlanService {
return resultList;
}
@Override
public void getPlanLock(OrderPlanLockReqVO orderPlanLockReqVO) {
Long planId = orderPlanLockReqVO.getPlanId();
String lockValInput = orderPlanLockReqVO.getVal();
PlanDO planDO = planMapper.selectById(planId);
AssertUtils.notEmpty(planDO, PLAN_NOT_EXISTS);
String planLockKey = String.format(ORDER_PLAN_OPTIMIZE_KEY, planId);
// 获取优化锁
String lockVal = stringRedisTemplate.opsForValue().get(planLockKey);
// 没有锁,尝试获取
if (StrUtil.isBlank(lockVal)) {
Boolean success = stringRedisTemplate.opsForValue().setIfAbsent(
planLockKey,
lockValInput,
Duration.ofMinutes(30)
);
if (Boolean.TRUE.equals(success)) {
return;
}
// 极端并发场景
lockVal = stringRedisTemplate.opsForValue().get(planLockKey);
}
// 用不同的lockKey去请求优化提示已锁单
if (!StrUtil.equals(lockVal, lockValInput)) {
throw exception(ORDER_PLAN_LOCKED);
}
}
@Override
public void releasePlanLock(OrderPlanLockReqVO orderPlanLockReqVO) {
Long planId = orderPlanLockReqVO.getPlanId();
String lockValInput = orderPlanLockReqVO.getVal();
String lockKey = String.format(ORDER_PLAN_OPTIMIZE_KEY, planId);
String lockVal = stringRedisTemplate.opsForValue().get(lockKey);
if (Objects.equals(lockVal, lockValInput)) {
stringRedisTemplate.delete(lockKey);
}
}
}