注意阅读策略模式和责任链模式的代码。
进入ordersDispatchService.dispatch(id)方法:
代码如下:
-
通过定时任务,每分钟执行一次dispatchDistributeJob()方法,代码如下:
import javax.annotation.Resource; import java.util.Set; import java.util.concurrent.Executor; import static com.jzo2o.orders.base.constants.RedisConstants.RedisKey.DISPATCH_LIST; /** * 派单分发xxl-job定时任务 */ @Component @Slf4j public class DispatchJobHandler { @Resource private RedisTemplate redisTemplate; @Resource(name = "dispatchExecutor") private Executor dispatchExecutor; // @Resource // private DispatchDistributeServiceImpl owner; @Resource private IOrdersDispatchService ordersDispatchService; @Resource private OrdersDispatchMapper ordersDispatchMapper; /** * 派单分发任务 */ @XxlJob("dispatch") public void dispatchDistributeJob(){ while (true) { Set<Long> ordersDispatchIds = redisTemplate.opsForZSet().rangeByScore(DISPATCH_LIST, 0, DateUtils.getCurrentTime(), 0, 100); log.info("ordersDispatchIds:{}", ordersDispatchIds); if (CollUtils.isEmpty(ordersDispatchIds)) { log.debug("当前没有可以派单数据"); return; } for (Long ordersDispatchId : ordersDispatchIds) { dispatch(ordersDispatchId); } try { Thread.sleep(1000); } catch (InterruptedException e) { throw new RuntimeException(e); } } } //由于一个订单3分钟处理一次,所以加锁控制3分钟内只加入线程池一次 @Lock(formatter = RedisConstants.RedisFormatter.JSONDISPATCHLIST,time = 180) public void dispatch(Long id) { dispatchExecutor.execute(() -> { ordersDispatchService.dispatch(id); }); } }
public void dispatch(Long id) { // 1.数据准备 // 1.1.获取订单信息 OrdersDispatch ordersDispatch = ordersDispatchService.getById(id); if (ordersDispatch == null) { // 订单不在直接删除 redisTemplate.opsForZSet().remove(DISPATCH_LIST, id); return; } // 1.3.服务时间,格式yyyyMMddHH int serveTime = ServeTimeUtils.getServeTimeInt(ordersDispatch.getServeStartTime()); // 1.4.区域调度配置 ConfigRegionInnerResDTO configRegionInnerResDTO = regionApi.findConfigRegionByCityCode(ordersDispatch.getCityCode()); // 1.5.获取派单规则 DispatchStrategyEnum dispatchStrategyEnum = DispatchStrategyEnum.of(configRegionInnerResDTO.getDispatchStrategy()); // 2.修改下次执行时间(默认3分钟),防止重复执行 ConfigRegionInnerResDTO configRegion = regionApi.findConfigRegionByCityCode(ordersDispatch.getCityCode()); redisTemplate.opsForZSet().incrementScore(DISPATCH_LIST, id, configRegion.getDispatchPerRoundInterval()); // 2.获取派单人员或机构 // 2.1.获取派单服务人员列表 List<ServeProviderDTO> serveProvidersOfServe = searchDispatchInfo(ordersDispatch.getCityCode(), ordersDispatch.getServeItemId(), 100, serveTime, dispatchStrategyEnum, ordersDispatch.getLon(), ordersDispatch.getLat(), 10); // 2.3.机构和服务人员列表合并,如果为空当前派单失败 log.info("派单筛选前数据,id:{},{}",id, serveProvidersOfServe); if (CollUtils.isEmpty(serveProvidersOfServe)) { log.info("id:{}匹配不到人",id); return; } // 3.派单过规则策略 // 3.1.获取派单策略 IDispatchStrategy dispatchStrategy = dispatchStrategyManager.get(dispatchStrategyEnum); // 3.2.过派单策略,并返回一个派单服务人员或机构 ServeProviderDTO serveProvider = dispatchStrategy.getPrecedenceServeProvider(serveProvidersOfServe); log.info("id:{},serveProvider : {}",id, JsonUtils.toJsonStr(serveProvider)); // // 4.机器抢单 OrderSeizeReqDTO orderSeizeReqDTO = new OrderSeizeReqDTO(); orderSeizeReqDTO.setSeizeId(id); orderSeizeReqDTO.setServeProviderId(serveProvider.getId()); orderSeizeReqDTO.setServeProviderType(serveProvider.getServeProviderType()); ordersSeizeApi.machineSeize(orderSeizeReqDTO); }
-
首先通过redisTemplate.opsForZSet().rangeByScore()方法取出派单池中的一批订单
-
调用 dispatch(Long id)方法通过线程池执行