How to Auto‑Cancel Unpaid Orders in Spring Boot: 3 Practical Approaches
This guide explains three ways to automatically cancel orders that remain unpaid for 30 minutes in a Spring Boot application, covering scheduled tasks, RabbitMQ delayed queues, and Redis key‑expiration events, with complete code examples and configuration details.
Problem
In e‑commerce and other online‑payment scenarios, an order that remains unpaid for more than 30 minutes should be automatically cancelled.
Solution 1 – Scheduled task
Use Spring Boot’s @Scheduled annotation to run a periodic job (e.g., every minute). The job queries the database for unpaid orders, checks the creation timestamp, and calls the order‑cancellation service for orders older than 30 minutes.
@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 – RabbitMQ delayed queue
When an order is created, push its identifier to a RabbitMQ delayed queue with a 30‑minute TTL. After the delay expires the consumer receives the message and invokes the cancellation logic.
@Service
public class OrderService {
@Autowired
private RabbitTemplate rabbitTemplate;
public void createOrder(Order order) {
saveOrderToDB(order);
rabbitTemplate.convertAndSend(
"orderDelayExchange",
"orderDelayKey",
order.getId(),
message -> {
message.getMessageProperties().setDelay(30 * 60 * 1000); // 30 min
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 key‑space expiration events
Store a temporary key for each order in Redis with a 30‑minute TTL (e.g., order:{id}). Enable key‑space notifications so Redis publishes an expired event. Spring Boot subscribes to the __keyevent@*__:expired channel, extracts the order id from the key, and cancels the order.
Enable notifications in redis.conf:
notify-keyspace-events "Ex"Spring configuration and service implementation:
@Configuration
public class RedisConfig {
@Autowired
private RedisConnectionFactory redisConnectionFactory;
@Bean
RedisMessageListenerContainer container() {
RedisMessageListenerContainer container = new RedisMessageListenerContainer();
container.setConnectionFactory(redisConnectionFactory);
container.addMessageListener((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;
}
}
@Service
public class OrderService {
@Autowired
private StringRedisTemplate redisTemplate;
public void createOrder(Order order) {
saveOrderToDB(order);
redisTemplate.opsForValue().set("order:" + order.getId(), order.getId(), 30, TimeUnit.MINUTES);
}
public void onOrderKeyExpired(String orderId) {
cancelOrder(orderId);
}
}Choosing a solution
All three approaches satisfy the 30‑minute automatic‑cancellation requirement. Use a scheduled task for simplicity when occasional scanning delay is acceptable. Choose a delayed queue for precise timing at the cost of an additional message‑broker dependency. Prefer Redis expiration events for real‑time cancellation with minimal overhead, provided key‑space notifications are enabled.
Signed-in readers can open the original source through BestHub's protected redirect.
This article has been distilled and summarized from source material, then republished for learning and reference. If you believe it infringes your rights, please contactand we will review it promptly.
Top Architect
Top Architect focuses on sharing practical architecture knowledge, covering enterprise, system, website, large‑scale distributed, and high‑availability architectures, plus architecture adjustments using internet technologies. We welcome idea‑driven, sharing‑oriented architects to exchange and learn together.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
