How to Auto‑Cancel Unpaid Orders in 30 Minutes with Spring Boot

This article explains three practical Spring Boot approaches—scheduled tasks, delayed RabbitMQ queues, and Redis key‑expiration events—to automatically cancel orders that remain unpaid for 30 minutes, complete with ready‑to‑use Java code examples.

Java High-Performance Architecture
Java High-Performance Architecture
Java High-Performance Architecture
How to Auto‑Cancel Unpaid Orders in 30 Minutes with Spring Boot

Introduction

In e‑commerce and other online‑payment applications, orders that remain unpaid after a certain period need to be automatically cancelled. This article introduces several ways to implement automatic cancellation of orders that are unpaid for 30 minutes using Spring Boot, with sample code.

Solution 1: Scheduled Task

Use Spring Boot’s @Scheduled annotation to run a periodic job that scans the database for unpaid orders older than 30 minutes and cancels them.

@Component
public class OrderCancelSchedule {

    @Autowired
    private OrderService orderService;

    @Scheduled(cron = "0 0/1 * * * ?")
    public void cancelUnpaidOrders() {
        List<Order> unpaidOrders = orderService.getUnpaidOrders();
        unpaidOrders.forEach(order -> {
            if (order.getCreationTime().plusMinutes(30).isBefore(LocalDateTime.now())) {
                orderService.cancelOrder(order.getId());
            }
        });
    }
}

Solution 2: Delayed Queue

Leverage a message‑queue system such as RabbitMQ with delayed‑message support. When an order is created, push its ID to a delayed queue set to expire after 30 minutes; the consumer then cancels the order.

@Service
public class OrderService {

    @Autowired
    private RabbitTemplate rabbitTemplate;

    public void createOrder(Order order) {
        // 保存订单至数据库
        saveOrderToDB(order);

        // 将订单ID推送至延迟队列
        rabbitTemplate.convertAndSend("orderDelayExchange", "orderDelayKey", order.getId(), message -> {
            message.getMessageProperties().setDelay(30 * 60 * 1000); // 设置延迟时间
            return message;
        });
    }
}

@Component
@RabbitListener(queues = "orderDelayQueue")
public class OrderDelayConsumer {

    @Autowired
    private OrderService orderService;

    @RabbitHandler
    public void process(String orderId) {
        // 取消订单
        orderService.cancelOrder(orderId);
    }
}

Solution 3: Redis Expiration Events

Store a key in Redis when an order is created, set its TTL to 30 minutes, and listen for key‑expiration events to trigger order cancellation.

@Service
public class OrderService {

    @Autowired
    private StringRedisTemplate redisTemplate;

    public void createOrder(Order order) {
        // 保存订单至数据库
        saveOrderToDB(order);

        // 在Redis中存储一个键,设置30分钟过期
        redisTemplate.opsForValue().set("order:" + order.getId(), order.getId(), 30, TimeUnit.MINUTES);
    }

    // 当键过期时,Redis会自动调用该方法(需要配置Redis的过期事件通知功能)
    public void onOrderKeyExpired(String orderId) {
        cancelOrder(orderId);
    }
}

Enable keyspace notifications in redis.conf with notify-keyspace-events "Ex", and configure a RedisMessageListenerContainer in Spring Boot to handle the __keyevent@*__:expired pattern.

@Configuration
public class RedisConfig {

    @Autowired
    private RedisConnectionFactory redisConnectionFactory;

    @Bean
    RedisMessageListenerContainer container() {
        RedisMessageListenerContainer container = new RedisMessageListenerContainer();
        container.setConnectionFactory(redisConnectionFactory);
        // 订阅所有db的过期事件
        container.addMessageListener(new MessageListener() {
            @Override
            public void onMessage(Message message, byte[] pattern) {
                String expiredKey = message.toString();
                if (expiredKey.startsWith("order:")) {
                    // 处理订单超时逻辑
                    String orderId = expiredKey.split(":")[1];
                    // orderService.cancelOrder(orderId);
                }
            }
        }, new PatternTopic("__keyevent@*__:expired"));
        return container;
    }
}

Conclusion

All three approaches can satisfy the 30‑minute unpaid‑order auto‑cancellation requirement. Choose the one that best fits your business needs, system load, and architectural constraints, as each has its own trade‑offs.

Original Source

Signed-in readers can open the original source through BestHub's protected redirect.

Sign in to view source
Republication Notice

This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactadmin@besthub.devand we will review it promptly.

JavaRedisSpring BootRabbitMQScheduled Taskorder cancellation
Java High-Performance Architecture
Written by

Java High-Performance Architecture

Sharing Java development articles and resources, including SSM architecture and the Spring ecosystem (Spring Boot, Spring Cloud, MyBatis, Dubbo, Docker), Zookeeper, Redis, architecture design, microservices, message queues, Git, etc.

0 followers
Reader feedback

How this landed with the community

Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.