CardCancellationScheduler.java

package uk.gov.dhsc.htbhf.claimant.scheduler;

import lombok.extern.slf4j.Slf4j;
import net.javacrumbs.shedlock.core.SchedulerLock;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import uk.gov.dhsc.htbhf.claimant.entity.Claim;
import uk.gov.dhsc.htbhf.claimant.repository.ClaimRepository;
import uk.gov.dhsc.htbhf.requestcontext.aop.NewRequestContextWithSessionId;

import java.time.LocalDate;
import java.time.Period;
import java.util.List;

import static uk.gov.dhsc.htbhf.logging.ExceptionDetailGenerator.constructExceptionDetail;

/**
 * Responsible for notifying claimants that their card is soon to be cancelled and creating a cancel card message.
 * All claims that have been in PENDING_CANCELLATION for 16 weeks or more will be updated to SCHEDULED_FOR_CANCELLATION
 * and have a notification sent.
 */
@Slf4j
@Component
public class CardCancellationScheduler {

    private final Period gracePeriod;
    private final ClaimRepository claimRepository;
    private final HandleCardPendingCancellationJob job;

    public CardCancellationScheduler(@Value("${card-cancellation.grace-period}") Period gracePeriod,
                                     ClaimRepository claimRepository,
                                     HandleCardPendingCancellationJob job) {
        this.gracePeriod = gracePeriod;
        this.claimRepository = claimRepository;
        this.job = job;
    }

    @Scheduled(cron = "${card-cancellation.schedule.cron-schedule}")
    @SchedulerLock(
            name = "Set cards to be cancelled",
            lockAtLeastForString = "${card-cancellation.schedule.minimum-lock-time}",
            lockAtMostForString = "${card-cancellation.schedule.maximum-lock-time}")
    @NewRequestContextWithSessionId(sessionId = "CardCancellationScheduler")
    public void handleCardsPendingCancellation() {
        log.trace("Querying for claims with a card status of pending cancellation since {}", LocalDate.now().minus(gracePeriod));
        List<Claim> claims = claimRepository.getClaimsWithCardStatusPendingCancellationOlderThan(gracePeriod);

        if (claims.isEmpty()) {
            log.trace("No cards to be scheduled for cancellation");
        } else {
            log.info("Processing {} cards to be scheduled for cancellation", claims.size());
            claims.forEach(this::handleCardPendingCancellation);
            log.debug("Finished scheduling {} cards for cancellation", claims.size());
        }
    }

    private void handleCardPendingCancellation(Claim claim) {
        try {
            job.handleCardPendingCancellation(claim);
        } catch (RuntimeException e) {
            log.error("Unable to handle card pending cancellation for claim {}: {}", claim.getId(), constructExceptionDetail(e), e);
        }
    }
}