CryptoScheduler.java

package com.distasilucas.cryptobalancetracker.scheduler;

import com.distasilucas.cryptobalancetracker.entity.Crypto;
import com.distasilucas.cryptobalancetracker.exception.TooManyRequestsException;
import com.distasilucas.cryptobalancetracker.service.CoingeckoService;
import com.distasilucas.cryptobalancetracker.service.CryptoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpStatus;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.web.client.RestClientResponseException;

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

@Slf4j
@Component
public class CryptoScheduler {

    private final int maxLimit;
    private final Clock clock;
    private final CryptoService cryptoService;
    private final CoingeckoService coingeckoService;

    public CryptoScheduler(
        @Value("${max-limit-crypto}") int maxLimit,
        Clock clock,
        CryptoService cryptoService,
        CoingeckoService coingeckoService
    ) {
        this.maxLimit = maxLimit;
        this.clock = clock;
        this.cryptoService = cryptoService;
        this.coingeckoService = coingeckoService;
    }

    @Scheduled(cron = "${update-crypto-info-cron}")
    public void updateCryptosInformation() {
        log.info("Running cron to update cryptos...");

        var cryptosToUpdate = getCryptosToUpdate()
            .stream()
            .map(this::mapCrypto)
            .toList();

        if (cryptosToUpdate.isEmpty()) {
            log.info("No cryptos to update");
        } else {
            log.info("About to update {} crypto(s)", cryptosToUpdate.size());

            cryptoService.updateCryptos(cryptosToUpdate);
        }
    }

    private List<Crypto> getCryptosToUpdate() {
        return cryptoService.findOldestNCryptosByLastPriceUpdate(LocalDateTime.now(clock).minusMinutes(5), maxLimit);
    }

    private Crypto mapCrypto(Crypto crypto) {
        try {
            var coingeckoCrypto = coingeckoService.retrieveCryptoInfo(crypto.getId());

            return new Crypto(coingeckoCrypto, LocalDateTime.now(clock));
        } catch (RestClientResponseException exception) {
            if (HttpStatus.TOO_MANY_REQUESTS == exception.getStatusCode()) {
                throw new TooManyRequestsException();
            } else {
                log.warn("A RestClientResponseException occurred while retrieving info for {}", crypto.getId(), exception);
                return crypto;
            }
        } catch (Exception exception) {
            log.error("An exception occurred while retrieving info for {}, therefore crypto info might be outdated", crypto.getId(), exception);

            return crypto;
        }
    }

}