第282集订单超时自动取消,最常见的方案架构实战:订单超时处理策略、定时任务与企业级订单超时取消解决方案
|字数总计:6.2k|阅读时长:29分钟|阅读量:
前言
订单超时自动取消作为电商系统的核心功能之一,直接影响着库存管理和用户体验。通过合理的订单超时处理策略和定时任务,能够构建一个高效、稳定、可扩展的订单超时取消系统,确保系统的稳定运行。本文从订单超时处理策略到定时任务,从基础实现到企业级应用,系统梳理订单超时自动取消的完整解决方案。
一、订单超时自动取消架构设计
1.1 订单超时处理整体架构
1.2 订单超时处理策略架构
二、订单超时处理策略实现
2.1 定时任务扫描策略
2.1.1 定时任务扫描服务
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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267
|
@Service public class OrderTimeoutScanService {
@Autowired private OrderRepository orderRepository;
@Autowired private RedisTemplate<String, Object> redisTemplate;
@Autowired private RabbitTemplate rabbitTemplate;
@Autowired private InventoryService inventoryService;
@Autowired private NotificationService notificationService;
private final String ORDER_TIMEOUT_CACHE_PREFIX = "order_timeout:"; private final int BATCH_SIZE = 100; private final int TIMEOUT_MINUTES = 30;
@Scheduled(fixedDelay = 60000) public void scanTimeoutOrders() { try { log.info("开始扫描超时订单");
List<Order> timeoutOrders = findTimeoutOrders();
if (timeoutOrders.isEmpty()) { log.info("没有发现超时订单"); return; }
log.info("发现{}个超时订单", timeoutOrders.size());
batchProcessTimeoutOrders(timeoutOrders);
log.info("超时订单扫描完成");
} catch (Exception e) { log.error("扫描超时订单失败", e); } }
private List<Order> findTimeoutOrders() { try { LocalDateTime timeoutTime = LocalDateTime.now().minusMinutes(TIMEOUT_MINUTES);
List<Order> timeoutOrders = orderRepository.findTimeoutOrders(timeoutTime);
return timeoutOrders;
} catch (Exception e) { log.error("查询超时订单失败", e); return new ArrayList<>(); } }
private void batchProcessTimeoutOrders(List<Order> timeoutOrders) { try { for (int i = 0; i < timeoutOrders.size(); i += BATCH_SIZE) { int endIndex = Math.min(i + BATCH_SIZE, timeoutOrders.size()); List<Order> batch = timeoutOrders.subList(i, endIndex);
CompletableFuture.runAsync(() -> { processBatchTimeoutOrders(batch); }); }
} catch (Exception e) { log.error("批量处理超时订单失败", e); } }
private void processBatchTimeoutOrders(List<Order> orders) { try { for (Order order : orders) { try { processTimeoutOrder(order); } catch (Exception e) { log.error("处理超时订单失败: {}", order.getOrderId(), e); } }
} catch (Exception e) { log.error("处理批量超时订单失败", e); } }
private void processTimeoutOrder(Order order) { try { if (!isOrderTimeout(order)) { return; }
updateOrderStatus(order);
releaseInventory(order);
sendTimeoutNotification(order);
recordTimeoutLog(order);
log.info("处理超时订单成功: {}", order.getOrderId());
} catch (Exception e) { log.error("处理超时订单失败: {}", order.getOrderId(), e); } }
private boolean isOrderTimeout(Order order) { try { if (order.getStatus() != OrderStatus.PENDING_PAYMENT) { return false; }
LocalDateTime timeoutTime = LocalDateTime.now().minusMinutes(TIMEOUT_MINUTES); if (order.getCreatedTime().isAfter(timeoutTime)) { return false; }
return true;
} catch (Exception e) { log.error("检查订单超时状态失败", e); return false; } }
private void updateOrderStatus(Order order) { try { order.setStatus(OrderStatus.CANCELLED); order.setCancelTime(LocalDateTime.now()); order.setCancelReason("订单超时自动取消"); order.setUpdatedTime(LocalDateTime.now());
orderRepository.save(order);
updateOrderCache(order);
} catch (Exception e) { log.error("更新订单状态失败", e); throw new OrderTimeoutException("更新订单状态失败", e); } }
private void releaseInventory(Order order) { try { CompletableFuture.runAsync(() -> { try { inventoryService.releaseInventory(order.getOrderId()); log.info("释放库存成功: {}", order.getOrderId()); } catch (Exception e) { log.error("释放库存失败: {}", order.getOrderId(), e); } });
} catch (Exception e) { log.error("释放库存失败", e); } }
private void sendTimeoutNotification(Order order) { try { OrderTimeoutNotification notification = new OrderTimeoutNotification(); notification.setOrderId(order.getOrderId()); notification.setUserId(order.getUserId()); notification.setOrderAmount(order.getAmount()); notification.setTimeoutTime(LocalDateTime.now()); notification.setNotificationType("ORDER_TIMEOUT");
rabbitTemplate.convertAndSend("order.timeout.notification.queue", notification);
} catch (Exception e) { log.error("发送超时通知失败", e); } }
private void recordTimeoutLog(Order order) { try { OrderTimeoutLog timeoutLog = new OrderTimeoutLog(); timeoutLog.setOrderId(order.getOrderId()); timeoutLog.setUserId(order.getUserId()); timeoutLog.setOrderAmount(order.getAmount()); timeoutLog.setTimeoutTime(LocalDateTime.now()); timeoutLog.setProcessTime(LocalDateTime.now());
CompletableFuture.runAsync(() -> { try { orderRepository.saveTimeoutLog(timeoutLog); } catch (Exception e) { log.error("记录超时日志失败", e); } });
} catch (Exception e) { log.error("记录超时日志失败", e); } }
private void updateOrderCache(Order order) { try { String cacheKey = ORDER_TIMEOUT_CACHE_PREFIX + order.getOrderId(); redisTemplate.opsForValue().set(cacheKey, order, Duration.ofHours(1));
} catch (Exception e) { log.error("更新订单缓存失败", e); } } }
|
2.2 延迟队列策略
2.2.1 延迟队列服务
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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285
|
@Service public class OrderTimeoutDelayQueueService {
@Autowired private RabbitTemplate rabbitTemplate;
@Autowired private RedisTemplate<String, Object> redisTemplate;
@Autowired private OrderRepository orderRepository;
private final String ORDER_TIMEOUT_DELAY_QUEUE = "order.timeout.delay.queue"; private final String ORDER_TIMEOUT_CACHE_PREFIX = "order_timeout_delay:"; private final int TIMEOUT_MINUTES = 30;
public void addOrderToDelayQueue(Order order) { try { validateOrder(order);
OrderTimeoutDelayMessage message = buildDelayMessage(order);
sendDelayMessage(message);
recordDelayQueueInfo(order);
log.info("订单添加到延迟队列成功: {}", order.getOrderId());
} catch (Exception e) { log.error("添加订单到延迟队列失败: {}", order.getOrderId(), e); } }
private void validateOrder(Order order) { if (order == null) { throw new IllegalArgumentException("订单不能为空"); }
if (order.getOrderId() == null) { throw new IllegalArgumentException("订单ID不能为空"); }
if (order.getStatus() != OrderStatus.PENDING_PAYMENT) { throw new IllegalArgumentException("订单状态不正确"); } }
private OrderTimeoutDelayMessage buildDelayMessage(Order order) { OrderTimeoutDelayMessage message = new OrderTimeoutDelayMessage(); message.setOrderId(order.getOrderId()); message.setUserId(order.getUserId()); message.setOrderAmount(order.getAmount()); message.setCreatedTime(order.getCreatedTime()); message.setTimeoutMinutes(TIMEOUT_MINUTES); message.setMessageId(UUID.randomUUID().toString()); message.setTimestamp(new Date());
return message; }
private void sendDelayMessage(OrderTimeoutDelayMessage message) { try { MessageProperties properties = new MessageProperties(); properties.setExpiration(String.valueOf(TIMEOUT_MINUTES * 60 * 1000)); properties.setMessageId(message.getMessageId()); properties.setTimestamp(new Date());
Message rabbitMessage = new Message(JSON.toJSONBytes(message), properties);
rabbitTemplate.send(ORDER_TIMEOUT_DELAY_QUEUE, rabbitMessage);
} catch (Exception e) { log.error("发送延迟消息失败", e); throw new OrderTimeoutException("发送延迟消息失败", e); } }
private void recordDelayQueueInfo(Order order) { try { String cacheKey = ORDER_TIMEOUT_CACHE_PREFIX + order.getOrderId(); OrderDelayQueueInfo queueInfo = new OrderDelayQueueInfo(); queueInfo.setOrderId(order.getOrderId()); queueInfo.setUserId(order.getUserId()); queueInfo.setAddTime(LocalDateTime.now()); queueInfo.setTimeoutTime(LocalDateTime.now().plusMinutes(TIMEOUT_MINUTES)); queueInfo.setStatus("PENDING");
redisTemplate.opsForValue().set(cacheKey, queueInfo, Duration.ofMinutes(TIMEOUT_MINUTES + 5));
} catch (Exception e) { log.error("记录延迟队列信息失败", e); } }
@RabbitListener(queues = "order.timeout.delay.queue") public void handleDelayMessage(OrderTimeoutDelayMessage message) { try { log.info("处理延迟队列消息: {}", message.getOrderId());
if (!isOrderStillPending(message.getOrderId())) { log.info("订单状态已变更,跳过处理: {}", message.getOrderId()); return; }
processTimeoutOrder(message);
updateDelayQueueInfo(message.getOrderId());
log.info("延迟队列消息处理完成: {}", message.getOrderId());
} catch (Exception e) { log.error("处理延迟队列消息失败: {}", message.getOrderId(), e); } }
private boolean isOrderStillPending(String orderId) { try { Order order = orderRepository.findByOrderId(orderId); return order != null && order.getStatus() == OrderStatus.PENDING_PAYMENT;
} catch (Exception e) { log.error("检查订单状态失败", e); return false; } }
private void processTimeoutOrder(OrderTimeoutDelayMessage message) { try { updateOrderStatus(message.getOrderId());
releaseInventory(message.getOrderId());
sendTimeoutNotification(message);
recordTimeoutLog(message);
} catch (Exception e) { log.error("处理超时订单失败", e); } }
private void updateOrderStatus(String orderId) { try { Order order = orderRepository.findByOrderId(orderId); if (order != null) { order.setStatus(OrderStatus.CANCELLED); order.setCancelTime(LocalDateTime.now()); order.setCancelReason("订单超时自动取消"); order.setUpdatedTime(LocalDateTime.now());
orderRepository.save(order); }
} catch (Exception e) { log.error("更新订单状态失败", e); } }
private void releaseInventory(String orderId) { try { CompletableFuture.runAsync(() -> { try { inventoryService.releaseInventory(orderId); } catch (Exception e) { log.error("释放库存失败", e); } });
} catch (Exception e) { log.error("释放库存失败", e); } }
private void sendTimeoutNotification(OrderTimeoutDelayMessage message) { try { OrderTimeoutNotification notification = new OrderTimeoutNotification(); notification.setOrderId(message.getOrderId()); notification.setUserId(message.getUserId()); notification.setOrderAmount(message.getOrderAmount()); notification.setTimeoutTime(LocalDateTime.now()); notification.setNotificationType("ORDER_TIMEOUT");
rabbitTemplate.convertAndSend("order.timeout.notification.queue", notification);
} catch (Exception e) { log.error("发送超时通知失败", e); } }
private void recordTimeoutLog(OrderTimeoutDelayMessage message) { try { OrderTimeoutLog timeoutLog = new OrderTimeoutLog(); timeoutLog.setOrderId(message.getOrderId()); timeoutLog.setUserId(message.getUserId()); timeoutLog.setOrderAmount(message.getOrderAmount()); timeoutLog.setTimeoutTime(LocalDateTime.now()); timeoutLog.setProcessTime(LocalDateTime.now()); timeoutLog.setProcessType("DELAY_QUEUE");
CompletableFuture.runAsync(() -> { try { orderRepository.saveTimeoutLog(timeoutLog); } catch (Exception e) { log.error("记录超时日志失败", e); } });
} catch (Exception e) { log.error("记录超时日志失败", e); } }
private void updateDelayQueueInfo(String orderId) { try { String cacheKey = ORDER_TIMEOUT_CACHE_PREFIX + orderId; OrderDelayQueueInfo queueInfo = (OrderDelayQueueInfo) redisTemplate.opsForValue().get(cacheKey);
if (queueInfo != null) { queueInfo.setStatus("PROCESSED"); queueInfo.setProcessTime(LocalDateTime.now()); redisTemplate.opsForValue().set(cacheKey, queueInfo, Duration.ofHours(1)); }
} catch (Exception e) { log.error("更新延迟队列信息失败", e); } } }
|
2.3 Redis过期策略
2.3.1 Redis过期服务
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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253
|
@Service public class OrderTimeoutRedisService {
@Autowired private RedisTemplate<String, Object> redisTemplate;
@Autowired private OrderRepository orderRepository;
@Autowired private RabbitTemplate rabbitTemplate;
private final String ORDER_TIMEOUT_REDIS_PREFIX = "order_timeout_redis:"; private final int TIMEOUT_MINUTES = 30;
public void setOrderTimeout(Order order) { try { validateOrder(order);
setRedisExpiration(order);
setExpirationCallback(order);
log.info("设置订单超时成功: {}", order.getOrderId());
} catch (Exception e) { log.error("设置订单超时失败: {}", order.getOrderId(), e); } }
private void validateOrder(Order order) { if (order == null) { throw new IllegalArgumentException("订单不能为空"); }
if (order.getOrderId() == null) { throw new IllegalArgumentException("订单ID不能为空"); }
if (order.getStatus() != OrderStatus.PENDING_PAYMENT) { throw new IllegalArgumentException("订单状态不正确"); } }
private void setRedisExpiration(Order order) { try { String cacheKey = ORDER_TIMEOUT_REDIS_PREFIX + order.getOrderId();
OrderTimeoutInfo timeoutInfo = new OrderTimeoutInfo(); timeoutInfo.setOrderId(order.getOrderId()); timeoutInfo.setUserId(order.getUserId()); timeoutInfo.setOrderAmount(order.getAmount()); timeoutInfo.setCreatedTime(order.getCreatedTime()); timeoutInfo.setTimeoutMinutes(TIMEOUT_MINUTES);
redisTemplate.opsForValue().set(cacheKey, timeoutInfo, Duration.ofMinutes(TIMEOUT_MINUTES));
} catch (Exception e) { log.error("设置Redis过期失败", e); throw new OrderTimeoutException("设置Redis过期失败", e); } }
private void setExpirationCallback(Order order) { try {
String callbackKey = ORDER_TIMEOUT_REDIS_PREFIX + order.getOrderId();
redisTemplate.getConnectionFactory().getConnection().setConfig("notify-keyspace-events", "Ex");
} catch (Exception e) { log.error("设置过期回调失败", e); } }
@EventListener public void handleRedisExpiration(RedisKeyExpiredEvent event) { try { String expiredKey = new String(event.getKeyspace());
if (expiredKey.startsWith(ORDER_TIMEOUT_REDIS_PREFIX)) { String orderId = expiredKey.substring(ORDER_TIMEOUT_REDIS_PREFIX.length());
log.info("检测到订单超时: {}", orderId);
processTimeoutOrder(orderId); }
} catch (Exception e) { log.error("处理Redis过期事件失败", e); } }
private void processTimeoutOrder(String orderId) { try { if (!isOrderStillPending(orderId)) { log.info("订单状态已变更,跳过处理: {}", orderId); return; }
updateOrderStatus(orderId);
releaseInventory(orderId);
sendTimeoutNotification(orderId);
recordTimeoutLog(orderId);
log.info("处理超时订单完成: {}", orderId);
} catch (Exception e) { log.error("处理超时订单失败: {}", orderId, e); } }
private boolean isOrderStillPending(String orderId) { try { Order order = orderRepository.findByOrderId(orderId); return order != null && order.getStatus() == OrderStatus.PENDING_PAYMENT;
} catch (Exception e) { log.error("检查订单状态失败", e); return false; } }
private void updateOrderStatus(String orderId) { try { Order order = orderRepository.findByOrderId(orderId); if (order != null) { order.setStatus(OrderStatus.CANCELLED); order.setCancelTime(LocalDateTime.now()); order.setCancelReason("订单超时自动取消"); order.setUpdatedTime(LocalDateTime.now());
orderRepository.save(order); }
} catch (Exception e) { log.error("更新订单状态失败", e); } }
private void releaseInventory(String orderId) { try { CompletableFuture.runAsync(() -> { try { inventoryService.releaseInventory(orderId); } catch (Exception e) { log.error("释放库存失败", e); } });
} catch (Exception e) { log.error("释放库存失败", e); } }
private void sendTimeoutNotification(String orderId) { try { Order order = orderRepository.findByOrderId(orderId); if (order != null) { OrderTimeoutNotification notification = new OrderTimeoutNotification(); notification.setOrderId(orderId); notification.setUserId(order.getUserId()); notification.setOrderAmount(order.getAmount()); notification.setTimeoutTime(LocalDateTime.now()); notification.setNotificationType("ORDER_TIMEOUT");
rabbitTemplate.convertAndSend("order.timeout.notification.queue", notification); }
} catch (Exception e) { log.error("发送超时通知失败", e); } }
private void recordTimeoutLog(String orderId) { try { Order order = orderRepository.findByOrderId(orderId); if (order != null) { OrderTimeoutLog timeoutLog = new OrderTimeoutLog(); timeoutLog.setOrderId(orderId); timeoutLog.setUserId(order.getUserId()); timeoutLog.setOrderAmount(order.getAmount()); timeoutLog.setTimeoutTime(LocalDateTime.now()); timeoutLog.setProcessTime(LocalDateTime.now()); timeoutLog.setProcessType("REDIS_EXPIRATION");
CompletableFuture.runAsync(() -> { try { orderRepository.saveTimeoutLog(timeoutLog); } catch (Exception e) { log.error("记录超时日志失败", e); } }); }
} catch (Exception e) { log.error("记录超时日志失败", e); } } }
|
三、企业级订单超时取消方案
3.1 订单超时管理服务
3.1.1 订单超时管理服务
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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
@Service public class OrderTimeoutManagementService {
@Autowired private OrderTimeoutScanService scanService;
@Autowired private OrderTimeoutDelayQueueService delayQueueService;
@Autowired private OrderTimeoutRedisService redisService;
@Autowired private RedisTemplate<String, Object> redisTemplate;
private final String ORDER_TIMEOUT_MANAGEMENT_CACHE_PREFIX = "order_timeout_management:"; private final long ORDER_TIMEOUT_MANAGEMENT_CACHE_EXPIRE = 3600;
public void processOrderTimeout(Order order, OrderTimeoutStrategy strategy) { try { validateOrder(order);
OrderTimeoutStrategy selectedStrategy = selectTimeoutStrategy(order, strategy);
executeTimeoutStrategy(order, selectedStrategy);
recordTimeoutStatistics(order, selectedStrategy);
log.info("订单超时处理完成: {}, 策略: {}", order.getOrderId(), selectedStrategy);
} catch (Exception e) { log.error("订单超时处理失败: {}", order.getOrderId(), e); } }
private OrderTimeoutStrategy selectTimeoutStrategy(Order order, OrderTimeoutStrategy strategy) { try { if (strategy != null) { return strategy; }
if (order.getAmount().compareTo(new BigDecimal("1000")) > 0) { return OrderTimeoutStrategy.DELAY_QUEUE; } else if (order.getAmount().compareTo(new BigDecimal("100")) > 0) { return OrderTimeoutStrategy.REDIS_EXPIRATION; } else { return OrderTimeoutStrategy.SCHEDULED_SCAN; }
} catch (Exception e) { log.error("选择超时处理策略失败", e); return OrderTimeoutStrategy.SCHEDULED_SCAN; } }
private void executeTimeoutStrategy(Order order, OrderTimeoutStrategy strategy) { try { switch (strategy) { case SCHEDULED_SCAN: break; case DELAY_QUEUE: delayQueueService.addOrderToDelayQueue(order); break; case REDIS_EXPIRATION: redisService.setOrderTimeout(order); break; default: throw new IllegalArgumentException("不支持的超时处理策略: " + strategy); }
} catch (Exception e) { log.error("执行超时处理策略失败", e); throw new OrderTimeoutException("执行超时处理策略失败", e); } }
private void validateOrder(Order order) { if (order == null) { throw new IllegalArgumentException("订单不能为空"); }
if (order.getOrderId() == null) { throw new IllegalArgumentException("订单ID不能为空"); }
if (order.getStatus() != OrderStatus.PENDING_PAYMENT) { throw new IllegalArgumentException("订单状态不正确"); } }
private void recordTimeoutStatistics(Order order, OrderTimeoutStrategy strategy) { try { OrderTimeoutStatistics statistics = new OrderTimeoutStatistics(); statistics.setOrderId(order.getOrderId()); statistics.setUserId(order.getUserId()); statistics.setOrderAmount(order.getAmount()); statistics.setStrategy(strategy); statistics.setProcessTime(LocalDateTime.now());
CompletableFuture.runAsync(() -> { try { orderRepository.saveTimeoutStatistics(statistics); } catch (Exception e) { log.error("记录超时统计失败", e); } });
} catch (Exception e) { log.error("记录超时统计失败", e); } }
public OrderTimeoutStatisticsResult getOrderTimeoutStatistics(Date startTime, Date endTime) { try { OrderTimeoutStatisticsResult result = new OrderTimeoutStatisticsResult(); result.setStartTime(startTime); result.setEndTime(endTime);
result.setTotalTimeoutOrders(1000L);
Map<OrderTimeoutStrategy, Long> strategyCount = new HashMap<>(); strategyCount.put(OrderTimeoutStrategy.SCHEDULED_SCAN, 400L); strategyCount.put(OrderTimeoutStrategy.DELAY_QUEUE, 300L); strategyCount.put(OrderTimeoutStrategy.REDIS_EXPIRATION, 300L); result.setStrategyCount(strategyCount);
result.setSuccessRate(0.98);
result.setAverageProcessTime(5000.0);
return result;
} catch (Exception e) { log.error("获取订单超时统计失败", e); throw new OrderTimeoutException("获取订单超时统计失败", e); } } }
|
四、性能优化与监控
4.1 性能优化
4.1.1 订单超时性能优化
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 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170
|
@Service public class OrderTimeoutPerformanceOptimizationService {
@Autowired private RedisTemplate<String, Object> redisTemplate;
@Autowired private CaffeineCache localCache;
private final String ORDER_TIMEOUT_PERFORMANCE_CACHE_PREFIX = "order_timeout_performance:";
public OrderTimeoutOptimizationResult optimizeOrderTimeoutPerformance(OrderTimeoutOptimizationRequest request) { try { OrderTimeoutOptimizationResult result = new OrderTimeoutOptimizationResult(); result.setRequestId(request.getRequestId()); result.setStartTime(new Date());
OrderTimeoutPatternAnalysis patternAnalysis = analyzeOrderTimeoutPattern(request); result.setPatternAnalysis(patternAnalysis);
OrderTimeoutStrategyOptimizationResult strategyOptimization = optimizeOrderTimeoutStrategy(request, patternAnalysis); result.setStrategyOptimization(strategyOptimization);
OrderTimeoutCacheOptimizationResult cacheOptimization = optimizeOrderTimeoutCacheStrategy(request, patternAnalysis); result.setCacheOptimization(cacheOptimization);
result.setStatus(OrderTimeoutOptimizationStatus.COMPLETED); result.setEndTime(new Date());
return result;
} catch (Exception e) { log.error("优化订单超时处理性能失败", e); throw new OrderTimeoutException("优化订单超时处理性能失败", e); } }
private OrderTimeoutPatternAnalysis analyzeOrderTimeoutPattern(OrderTimeoutOptimizationRequest request) { try { OrderTimeoutPatternAnalysis analysis = new OrderTimeoutPatternAnalysis(); analysis.setRequestId(request.getRequestId());
analysis.setTimeoutFrequency(analyzeOrderTimeoutFrequency(request.getOrderId()));
analysis.setOrderCharacteristics(analyzeOrderCharacteristics(request.getOrderId()));
return analysis;
} catch (Exception e) { log.error("分析订单超时模式失败", e); throw new OrderTimeoutException("分析订单超时模式失败", e); } }
private OrderTimeoutFrequency analyzeOrderTimeoutFrequency(String orderId) { try { OrderTimeoutFrequency frequency = new OrderTimeoutFrequency(); frequency.setOrderId(orderId); frequency.setDailyCount(100); frequency.setHourlyCount(10); frequency.setMinuteCount(1);
return frequency;
} catch (Exception e) { log.error("分析订单超时频率失败", e); return new OrderTimeoutFrequency(); } }
private OrderCharacteristics analyzeOrderCharacteristics(String orderId) { try { OrderCharacteristics characteristics = new OrderCharacteristics(); characteristics.setOrderId(orderId); characteristics.setOrderAmount(new BigDecimal("1000")); characteristics.setOrderType("NORMAL"); characteristics.setPriority(1);
return characteristics;
} catch (Exception e) { log.error("分析订单特征失败", e); return new OrderCharacteristics(); } }
private OrderTimeoutStrategyOptimizationResult optimizeOrderTimeoutStrategy(OrderTimeoutOptimizationRequest request, OrderTimeoutPatternAnalysis analysis) { try { OrderTimeoutStrategyOptimizationResult result = new OrderTimeoutStrategyOptimizationResult(); result.setRequestId(request.getRequestId());
if (analysis.getOrderCharacteristics().getOrderAmount().compareTo(new BigDecimal("1000")) > 0) { result.setRecommendedStrategy(OrderTimeoutStrategy.DELAY_QUEUE); result.setRecommendedTimeoutMinutes(30); result.setRecommendedBatchSize(50); } else if (analysis.getOrderCharacteristics().getOrderAmount().compareTo(new BigDecimal("100")) > 0) { result.setRecommendedStrategy(OrderTimeoutStrategy.REDIS_EXPIRATION); result.setRecommendedTimeoutMinutes(30); result.setRecommendedBatchSize(100); } else { result.setRecommendedStrategy(OrderTimeoutStrategy.SCHEDULED_SCAN); result.setRecommendedTimeoutMinutes(30); result.setRecommendedBatchSize(200); }
return result;
} catch (Exception e) { log.error("优化订单超时策略失败", e); throw new OrderTimeoutException("优化订单超时策略失败", e); } }
private OrderTimeoutCacheOptimizationResult optimizeOrderTimeoutCacheStrategy(OrderTimeoutOptimizationRequest request, OrderTimeoutPatternAnalysis analysis) { try { OrderTimeoutCacheOptimizationResult result = new OrderTimeoutCacheOptimizationResult(); result.setRequestId(request.getRequestId());
if (analysis.getTimeoutFrequency().getDailyCount() > 100) { result.setRecommendedCacheExpire(3600); result.setRecommendedCacheSize(1000); result.setRecommendedCacheStrategy("LRU"); } else if (analysis.getTimeoutFrequency().getDailyCount() > 10) { result.setRecommendedCacheExpire(1800); result.setRecommendedCacheSize(500); result.setRecommendedCacheStrategy("LFU"); } else { result.setRecommendedCacheExpire(600); result.setRecommendedCacheSize(100); result.setRecommendedCacheStrategy("FIFO"); }
return result;
} catch (Exception e) { log.error("优化订单超时缓存策略失败", e); throw new OrderTimeoutException("优化订单超时缓存策略失败", e); } } }
|
4.2 监控告警
4.2.1 订单超时监控指标
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
|
@Component public class OrderTimeoutMetrics {
private final MeterRegistry meterRegistry;
public OrderTimeoutMetrics(MeterRegistry meterRegistry) { this.meterRegistry = meterRegistry; }
public void recordOrderTimeoutCount(String strategy, String status) { Counter.builder("order_timeout.count") .description("订单超时次数") .tag("strategy", strategy) .tag("status", status) .register(meterRegistry) .increment(); }
public void recordOrderTimeoutProcessTime(String strategy, String status, long duration) { Timer.builder("order_timeout.process.time") .description("订单超时处理时间") .tag("strategy", strategy) .tag("status", status) .register(meterRegistry) .record(duration, TimeUnit.MILLISECONDS); }
public void recordOrderTimeoutSuccessRate(String strategy, double successRate) { Gauge.builder("order_timeout.success.rate") .description("订单超时成功率") .tag("strategy", strategy) .register(meterRegistry, successRate); }
public void recordOrderTimeoutFailureRate(String strategy, double failureRate) { Gauge.builder("order_timeout.failure.rate") .description("订单超时失败率") .tag("strategy", strategy) .register(meterRegistry, failureRate); }
public void recordOrderTimeoutThroughput(String strategy, double throughput) { Gauge.builder("order_timeout.throughput") .description("订单超时吞吐量") .tag("strategy", strategy) .register(meterRegistry, throughput); }
public void recordOrderTimeoutExceptionCount(String strategy, String exceptionType) { Counter.builder("order_timeout.exception.count") .description("订单超时异常次数") .tag("strategy", strategy) .tag("exception_type", exceptionType) .register(meterRegistry) .increment(); } }
|
4.2.2 订单超时告警规则
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
| groups: - name: order_timeout_alerts rules: - alert: HighOrderTimeoutProcessTime expr: order_timeout_process_time{quantile="0.95"} > 10000 for: 2m labels: severity: warning annotations: summary: "订单超时处理时间过长" description: "订单超时处理时间P95超过10秒,当前值: {{ $value }}ms" - alert: HighOrderTimeoutFailureRate expr: order_timeout_failure_rate > 0.05 for: 2m labels: severity: warning annotations: summary: "订单超时失败率过高" description: "订单超时失败率超过5%,当前值: {{ $value }}" - alert: LowOrderTimeoutThroughput expr: order_timeout_throughput < 10 for: 5m labels: severity: warning annotations: summary: "订单超时吞吐量过低" description: "订单超时吞吐量低于10次/秒,当前值: {{ $value }}" - alert: HighOrderTimeoutExceptionCount expr: rate(order_timeout_exception_count[5m]) > 5 for: 2m labels: severity: critical annotations: summary: "订单超时异常次数过多" description: "订单超时异常频率超过5次/分钟,当前值: {{ $value }}" - alert: OrderTimeoutServiceDown expr: up{job="order-timeout-service"} == 0 for: 1m labels: severity: critical annotations: summary: "订单超时服务宕机" description: "订单超时服务已宕机超过1分钟"
|
五、总结
订单超时自动取消作为电商系统的核心功能之一,通过合理的订单超时处理策略和定时任务,能够构建一个高效、稳定、可扩展的订单超时取消系统。本文从订单超时处理策略到定时任务,从基础实现到企业级应用,系统梳理了订单超时自动取消的完整解决方案。
5.1 关键要点
- 处理策略:通过多种处理策略实现不同场景下的订单超时取消需求
- 定时任务:通过定时任务扫描、延迟队列、Redis过期等方式处理超时订单
- 性能优化:通过批量处理、异步处理、缓存优化等手段优化处理性能
- 监控告警:建立完善的监控体系,及时发现和处理问题
- 企业级方案:提供完整的企业级部署和监控方案
5.2 最佳实践
- 策略选择:根据订单金额、处理频率、系统负载选择合适的处理策略
- 批量处理:合理使用批量处理,提高处理效率
- 异步处理:通过异步处理提高系统响应性能
- 监控告警:建立完善的监控体系,确保订单超时处理服务稳定运行
- 容错处理:实现完善的容错机制,确保系统稳定性
通过以上措施,可以构建一个高效、稳定、可扩展的订单超时自动取消系统,为企业的各种业务场景提供订单超时处理支持。