ReservationExpiryJob.java

package com.ecommerce.inventory.application.service;

import com.ecommerce.inventory.infrastructure.config.InventorySchedulingConfig;
import com.ecommerce.inventory.application.exception.InventoryException;
import com.ecommerce.inventory.infrastructure.config.ReservationProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

@Component
@ConditionalOnProperty(
        prefix = "ecommerce.inventory.reservation",
        name = "expiry-enabled",
        havingValue = "true",
        matchIfMissing = true)
public class ReservationExpiryJob {

    private static final Logger log = LoggerFactory.getLogger(ReservationExpiryJob.class);

    private final InventoryService inventoryService;
    private final ReservationProperties properties;

    public ReservationExpiryJob(InventoryService inventoryService, ReservationProperties properties) {
        this.inventoryService = inventoryService;
        this.properties = properties;
    }

    @Scheduled(
            fixedDelayString = "${ecommerce.inventory.reservation.expiry-scan-delay:5000}",
            scheduler = InventorySchedulingConfig.CONTROL_SCHEDULER)
    public void expireReservations() {
        for (String reservationNo : inventoryService.findExpiredReservationNumbers(properties.expiryBatchSize())) {
            try {
                inventoryService.expireReservation(reservationNo);
            } catch (InventoryException exception) {
                log.debug("Reservation expiration lost a state race: reservationNo={}, code={}",
                        reservationNo, exception.error().code());
            }
        }
    }
}