package com.danielbohry.stocks.service.stock; import com.danielbohry.stocks.domain.StockHistory; import com.danielbohry.stocks.exception.BadRequestException; import com.danielbohry.stocks.repository.stock.StockHistoryRepository; import lombok.AllArgsConstructor; import net.javacrumbs.shedlock.spring.annotation.SchedulerLock; import org.springframework.cache.annotation.Cacheable; import org.springframework.scheduling.annotation.Scheduled; import org.springframework.stereotype.Service; import java.time.Instant; import java.util.List; import static java.time.Instant.now; import static java.time.temporal.ChronoUnit.DAYS; @Service @AllArgsConstructor public class StockHistoryService { private final StockService service; private final StockHistoryRepository repository; public static final String ONCE_PER_DAY_AT_11PM = "0 0 23 * * *"; @Scheduled(cron = ONCE_PER_DAY_AT_11PM) @SchedulerLock(name = "StockQuoteService_saveQuotes", lockAtLeastFor = "PT5M", lockAtMostFor = "PT15M") public void saveQuotes() { List stocks = service.getAll().stream() .map(stock -> new StockHistory(stock.getCode(), stock.getCurrency(), stock.getPrice(), now())) .toList(); repository.saveAll(stocks); } @Cacheable(value = "stockHistory", key = "#code + '-' + #range") public List get(String code, String range) { Instant end = Instant.now(); Instant start = switch (range) { case "5d" -> end.minus(5, DAYS); case "30d" -> end.minus(30, DAYS); case "6m" -> end.minus(180, DAYS); case "1y" -> end.minus(365, DAYS); default -> throw new BadRequestException("Unsupported range: " + range); }; return repository.findByCodeAndCreatedAtBetween(code, start, end); } }