laitimes

How to solve the problem of automatic cancellation of orders when they expire in the Spring Boot Marketplace project?

How to solve the problem of automatic cancellation of orders when they expire in the Spring Boot Marketplace project?

The automatic cancellation function of order timeout is mainly used in the e-commerce online service platform to ensure that inventory resources can be automatically released, and in order to ensure the user experience of an optimized implementation method. The main problem to solve is that if the user does not complete the payment operation within the time set by the order, then the system will set the order to a canceled or overdue payment status.

Order timeout logic handles details

First of all, at the beginning of the order creation, the order is in a pending state, if the order is successfully paid according to the normal process, then the status of the order will be updated to paid, and if there is a timeout of time not paid, then the order status will change to the status of canceled.

That is to say, when the order is created, there needs to be a time field to record the time when the order was created, and another field needs to be set to record the time point when the order is timed.

When the order is created, all the inventory of the goods will be temporarily locked, that is to say, the inventory will be deducted, but whether the final deduction is true still needs to wait for the order to be paid successfully, if the order payment is successful, then the inventory will be deducted normally, if the order is canceled or the order is automatically canceled, then the inventory will be automatically released.

How to solve the problem of automatic cancellation of order timeout? Let's take a look at a few implementations.

使用定时任务 (Scheduled Task)

In Spring Boot, timed task operations are provided, and developers can use @Scheduled annotations to execute the logic of canceling timed out orders at regular intervals. It is shown below.

Create a timed task class and write the logic to check and cancel timeout orders.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;

@Component
public class OrderTimeoutTask {

    @Autowired
    private OrderService orderService;

    // 每隔1小时执行一次
    @Scheduled(fixedRate = 3600000)
    public void cancelTimeoutOrders() {
        LocalDateTime now = LocalDateTime.now();
        // 假设订单超时时间为2小时
        LocalDateTime timeoutThreshold = now.minusHours(2);
        orderService.cancelOrdersBefore(timeoutThreshold);
    }
}
           

Implement the method of canceling timed out orders in the OrderService.

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Service
public class OrderService {

    @Autowired
    private OrderRepository orderRepository;

    public void cancelOrdersBefore(LocalDateTime timeoutThreshold) {
        List<Order> timeoutOrders = orderRepository.findByStatusAndCreateTimeBefore("PENDING", timeoutThreshold);
        for (Order order : timeoutOrders) {
            order.setStatus("CANCELLED");
            orderRepository.save(order);
        }
    }
}
           

The advantage of this method is that the implementation is relatively simple, and you can directly use SpringBoot timing tasks, which does not require additional system deployment consumption, but we can also see that in the case of some large order volumes, if the scheduled task is executed in the above way, the consumption of system resources itself is relatively large, and in addition, in the above operation, we also see that the time of the scheduled task execution is fixed, and there may be a problem of delayed operation.

Therefore, this method is suitable for some small and medium-sized projects, where the order volume is not too large, the business logic processing is not too complex, and the real-time processing of order timeout is not too high.

使用消息队列 (Message Queue)

You can use message queues to handle order timeouts more flexibly and efficiently, such as RabbitMQ and Kafka. As shown below, RabbitMQ is used to process the timeout of an order.

import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void createOrder(Order order) {
        // 保存订单
        orderRepository.save(order);

        // 发送延时消息
        rabbitTemplate.convertAndSend("order.exchange", "order.timeout", order.getId(), message -> {
            message.getMessageProperties().setDelay(7200000); // 设置延时2小时
            return message;
        });
    }
}           

Service consumer code

import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class OrderTimeoutConsumer {

    @Autowired
    private OrderService orderService;

    @RabbitListener(queues = "order.timeout.queue")
    public void handleOrderTimeout(Long orderId) {
        orderService.cancelOrderById(orderId);
    }
}           

The advantage of this method is that it is more flexible, which is more suitable for some high-concurrency scenarios, and it also controls the real-time nature of data processing very well, and the order can be processed immediately after the order timeout, avoiding the impact of peak traffic on the system.

However, the disadvantage is also obvious, that is, additional maintenance of the message queue is required, which virtually increases the complexity of the system, in this case, the reliability of the system message cannot be guaranteed, and the problem of duplicate processing may occur due to network problems.

This method is suitable for some large-scale mall applications, after all, it is a large-scale system, complexity is no longer a problem, in some scenarios with large traffic and high concurrency, traffic peak shaving can also be carried out through message queues, and the use of message queues can also make the system have higher scalability.

Using the Database Scheduler

If you are using MySQL, you can use the Event Scheduler of MySQL to execute SQL statements on a scheduled basis. It is shown below.

启用MySQL Event Scheduler

SET GLOBAL event_scheduler = ON;           

Write a SQL event to check for timeout and cancel the timeout order

CREATE EVENT cancel_timeout_orders
ON SCHEDULE EVERY 1 HOUR
DO
    UPDATE orders
    SET status = 'CANCELLED'
    WHERE status = 'PENDING' AND create_time < NOW() - INTERVAL 2 HOUR;           

This method is equivalent to a scheduled task in the database, which is relatively simple to implement, does not require processing at the logical layer, and has low development costs.

However, because it is a database operation, it may cause greater pressure on the database and reduce performance, and the performance difference for different databases is also very large, and these tasks need to be rewritten when performing database migration, wasting time.

This kind of operation is suitable for some small applications, which have a strong dependence on the database, a relatively small order volume, and the database can support such operations.

summary

  • Scheduled Tasks: Ideal for small and medium-sized applications with moderate order volumes and low real-time requirements. The implementation is simple, but it can cause problems with database load when processing a large number of orders.
  • Message Queue: It is suitable for large, high-concurrency applications that require high real-time performance. It has good scalability and real-time, but requires additional configuration and maintenance.
  • Database Scheduler: This is suitable for small applications where the database supports scheduling functions and the order volume is small. The implementation is simple and straightforward, but the scalability is poor.

We can choose the appropriate implementation method according to the scale of the project, the size of the order, the requirements of real-time and other scenarios.

Read on