feat(health):新增延时队列处理超时订单

This commit is contained in:
JIAN 2024-09-19 19:46:10 +08:00
parent 084455fd76
commit b4d10a7306
6 changed files with 152 additions and 8 deletions

View File

@ -6,8 +6,8 @@
<groupId>com.jzo2o</groupId>
<artifactId>jzo2o-health</artifactId>
<version>1.0-SNAPSHOT</version>
<name>health</name>
<description>health</description>
<name>jzo2o-health</name>
<description>jzo2o-health</description>
<parent>
<artifactId>jzo2o-parent</artifactId>
@ -100,4 +100,4 @@
</plugins>
</build>
</project>
</project>

View File

@ -0,0 +1,61 @@
package com.jzo2o.health.config;
import com.jzo2o.health.constant.HealthMqConstants;
import com.jzo2o.rabbitmq.config.RabbitMqConfiguration;
import org.springframework.amqp.core.*;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import java.util.concurrent.TimeUnit;
/**
* RabbitMQ延时队列
* @author JIAN
*/
@Configuration
@Import(RabbitMqConfiguration.class)
public class DelayQueueConfiguration {
@Bean
public Exchange delayExchange() {
return ExchangeBuilder
.topicExchange(HealthMqConstants.Exchanges.HEALTH_ORDER)
.durable(true)
.build();
}
@Bean
public Queue delayQueueIn() {
return QueueBuilder
.durable(HealthMqConstants.Queues.DELAY_IN)
// 订单默认15分钟超时
.ttl((int) TimeUnit.MINUTES.toMillis(15))
.deadLetterExchange(HealthMqConstants.Exchanges.HEALTH_ORDER)
.deadLetterRoutingKey(HealthMqConstants.RoutingKeys.ORDER_OVERTIME_OUT)
.build();
}
@Bean
public Queue delayQueueOut() {
return QueueBuilder.durable(HealthMqConstants.Queues.DELAY_OUT)
.build();
}
@Bean
public Binding bindDelayQueueIn() {
return BindingBuilder
.bind(delayQueueIn())
.to(delayExchange())
.with(HealthMqConstants.RoutingKeys.ORDER_OVERTIME_IN)
.noargs();
}
@Bean
public Binding bindDelayQueueOut() {
return BindingBuilder
.bind(delayQueueOut())
.to(delayExchange())
.with(HealthMqConstants.RoutingKeys.ORDER_OVERTIME_OUT)
.noargs();
}
}

View File

@ -0,0 +1,23 @@
package com.jzo2o.health.constant;
import com.jzo2o.common.constants.MqConstants;
/**
* 即刻体检MQ常量
* @author JIAN
*/
public interface HealthMqConstants extends MqConstants {
interface Exchanges extends MqConstants.Exchanges {
String HEALTH_ORDER = "health.exchange.topic.order";
}
interface Queues extends MqConstants.Queues {
String DELAY_IN = "health.queue.orders.delay.in";
String DELAY_OUT = "health.queue.orders.delay.out";
}
interface RoutingKeys extends MqConstants.RoutingKeys {
String ORDER_OVERTIME_IN = "order.overtime.in";
String ORDER_OVERTIME_OUT = "order.overtime.out";
}
}

View File

@ -1,17 +1,25 @@
package com.jzo2o.health.listener;
import com.jzo2o.api.trade.TradingApi;
import com.jzo2o.api.trade.dto.response.TradingResDTO;
import com.jzo2o.api.trade.enums.TradingStateEnum;
import com.jzo2o.common.constants.MqConstants;
import com.jzo2o.common.constants.UserType;
import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.model.msg.TradeStatusMsg;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.JsonUtils;
import com.jzo2o.common.utils.ObjectUtils;
import com.jzo2o.health.constant.HealthMqConstants;
import com.jzo2o.health.constant.TradeConstants;
import com.jzo2o.health.enums.OrderPayStatusEnum;
import com.jzo2o.health.enums.OrderStatusEnum;
import com.jzo2o.health.model.OrderUpdateStatusDTO;
import com.jzo2o.health.model.domain.Orders;
import com.jzo2o.health.model.domain.OrdersCancelled;
import com.jzo2o.health.service.IOrderCancelService;
import com.jzo2o.health.service.IOrderCommonService;
import com.jzo2o.health.service.IOrderCreateService;
import com.jzo2o.health.service.IReservationSettingService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.rabbit.annotation.Exchange;
@ -37,6 +45,12 @@ public class OrderStatusListener {
private IOrderCommonService orderCommonService;
@Resource
private TransactionTemplate transactionTemplate;
@Resource
private IOrderCancelService orderCancelService;
@Resource
private IReservationSettingService reservationSettingService;
@Resource
private TradingApi tradingApi;
/**
* 接收支付成功信息
@ -44,10 +58,10 @@ public class OrderStatusListener {
*/
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = TradeConstants.MQ_TRADE_QUEUE),
exchange = @Exchange(name = MqConstants.Exchanges.TRADE, type = ExchangeTypes.TOPIC),
key = MqConstants.RoutingKeys.TRADE_UPDATE_STATUS))
exchange = @Exchange(name = HealthMqConstants.Exchanges.TRADE, type = ExchangeTypes.TOPIC),
key = HealthMqConstants.RoutingKeys.TRADE_UPDATE_STATUS))
public void listenTradeUpdatePayStatusMsg(String msg) {
log.info("接收到支付结果状态的消息 ({})-> {}", MqConstants.Queues.ORDERS_TRADE_UPDATE_STATUS, msg);
log.info("接收到支付结果状态的消息 ({})-> {}", HealthMqConstants.Queues.ORDERS_TRADE_UPDATE_STATUS, msg);
List<TradeStatusMsg> msgList = JsonUtils.parseArray(msg).toList(TradeStatusMsg.class);
if (CollUtils.isEmpty(msgList)) {
@ -76,4 +90,44 @@ public class OrderStatusListener {
}
});
}
@RabbitListener(bindings = @QueueBinding(
value = @Queue(name = HealthMqConstants.Queues.DELAY_OUT),
exchange = @Exchange(name = HealthMqConstants.Exchanges.HEALTH_ORDER, type = ExchangeTypes.TOPIC),
key = HealthMqConstants.RoutingKeys.ORDER_OVERTIME_OUT))
public void handleOverTimeOrder(String msg) {
Long orderId = Long.parseLong(msg);
if (ObjectUtils.isEmpty(orderId)) {
return;
}
Orders order = orderCommonService.getById(orderId);
if (ObjectUtils.isEmpty(order)) {
return;
}
if (order.getOrderStatus() == OrderStatusEnum.NO_PAY && order.getPayStatus() == OrderPayStatusEnum.NO_PAY) {
Long tradingOrderNo = order.getTradingOrderNo();
if (ObjectUtils.isNotEmpty(tradingOrderNo)) {
// 再次请求防止已支付
TradingResDTO tradingResDTO = tradingApi.findTradResultByTradingOrderNo(tradingOrderNo);
if (ObjectUtils.isNotEmpty(tradingResDTO) && tradingResDTO.getTradingState() == TradingStateEnum.YJS) {
return;
}
}
// 事务更新数据表(取消订单)
transactionTemplate.executeWithoutResult(status -> {
orderCancelService.cancelOrder(OrdersCancelled.builder()
.id(orderId)
.cancelTime(LocalDateTime.now())
.cancelReason("订单超时自动取消")
.cancellerType(UserType.SYSTEM)
.build());
// 已预约人数 - 1
reservationSettingService.plusReservationCount(order.getReservationDate(), -1);
});
}
}
}

View File

@ -30,6 +30,7 @@ import com.jzo2o.health.model.dto.response.OrdersPayResDTO;
import com.jzo2o.health.model.dto.response.PlaceOrderResDTO;
import com.jzo2o.health.properties.TradeProperties;
import com.jzo2o.health.service.*;
import com.jzo2o.rabbitmq.client.RabbitClient;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
@ -64,6 +65,8 @@ public class OrderCreateServiceImpl extends ServiceImpl<OrdersMapper, Orders> im
private RedisTemplate<String, Long> redisTemplate;
@Resource
private TransactionTemplate transactionTemplate;
@Resource
private RabbitClient rabbitClient;
/**
* 生成订单号(2位年+2位月+2位日+13位序号)
@ -125,6 +128,9 @@ public class OrderCreateServiceImpl extends ServiceImpl<OrdersMapper, Orders> im
reservationSettingService.plusReservationCount(placeOrderReqDTO.getReservationDate(), 1);
});
// 发送消息到延时队列处理超时订单(发送检测的订单id)
rabbitClient.sendMsg("health.exchange.topic.order", "order.overtime.in", orderId.toString());
return new PlaceOrderResDTO(orderId);
}

View File

@ -100,7 +100,7 @@ public class ReservationSettingServiceImpl extends ServiceImpl<ReservationSettin
@Override
public void plusReservationCount(LocalDate time, Integer count) {
if (SqlHelper.retBool(baseMapper.plusReservationCount(time, count))) {
if (!SqlHelper.retBool(baseMapper.plusReservationCount(time, count))) {
throw new CommonException("预约人数已满不能预约");
}
}