Skip to content

Commit

Permalink
fix: timeouts
Browse files Browse the repository at this point in the history
  • Loading branch information
Angular2Guy committed Aug 29, 2024
1 parent 7fed53f commit 05a528f
Show file tree
Hide file tree
Showing 10 changed files with 58 additions and 43 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package ch.xxx.manager.adapter.client;

import java.time.Duration;
import java.util.Optional;

import org.slf4j.Logger;
Expand Down Expand Up @@ -50,7 +51,7 @@ public Optional<AlphaOverviewImportDto> importCompanyProfile(String symbol) {
final String myUrl = String.format("https://www.alphavantage.co/query?function=OVERVIEW&symbol=%s&apikey=%s",
symbol, this.apiKey);
LOGGER.info(myUrl);
return this.connectorClient.restCall(myUrl, AlphaOverviewImportDto.class);
return this.connectorClient.restCall(myUrl, AlphaOverviewImportDto.class, Duration.ofMillis(100));
}

@Override
Expand All @@ -61,6 +62,6 @@ public Optional<DailyFxWrapperImportDto> getFxTimeseriesDailyHistory(String to_c
"https://www.alphavantage.co/query?function=FX_DAILY&from_symbol=%s&to_symbol=%s%s&apikey=%s",
from_currency, to_currency, fullSeriesStr, this.apiKey);
LOGGER.info(myUrl);
return this.connectorClient.restCall(myUrl, DailyFxWrapperImportDto.class);
return this.connectorClient.restCall(myUrl, DailyFxWrapperImportDto.class, Duration.ofMillis(100));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,16 @@
*/
package ch.xxx.manager.adapter.client;

import java.time.Duration;
import java.util.Optional;

import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.stereotype.Component;
Expand All @@ -29,6 +32,7 @@

@Component
public class ConnectorClient {
private static final Logger LOGGER = LoggerFactory.getLogger(ConnectorClient.class);
private RestClient restClient;

public ConnectorClient() {
Expand All @@ -42,24 +46,42 @@ public ConnectorClient() {
this.restClient = RestClient.builder().requestFactory(factory).build();
}

public <T> Optional<T> restCall(String url, Class<T> typeClass, Duration delay) {
return restCall(url, new LinkedMultiValueMap<String, String>(), typeClass, delay);
}

public <T> Optional<T> restCall(String url, Class<T> typeClass) {
return restCall(url, new LinkedMultiValueMap<String, String>(), typeClass);
return restCall(url, new LinkedMultiValueMap<String, String>(), typeClass, Duration.ZERO);
}

public <T> Optional<T> restCall(String url, ParameterizedTypeReference<T> valueTypeRef) {
return restCall(url, new LinkedMultiValueMap<String, String>(), valueTypeRef);
}

public <T> Optional<T> restCall(String url, MultiValueMap<String, String> headerValues, Class<T> typeClass) {
return Optional.ofNullable(createCall(url, headerValues).toEntity(typeClass).getBody());
public <T> Optional<T> restCall(String url, MultiValueMap<String, String> headerValues, Class<T> typeClass, Duration delay) {
return Optional.ofNullable(createCall(url, headerValues, delay).toEntity(typeClass).getBody());
}

public <T> Optional<T> restCall(String url, MultiValueMap<String, String> headerValues,
ParameterizedTypeReference<T> valueTypeRef) {
return Optional.ofNullable(createCall(url, headerValues).body(valueTypeRef));
return Optional.ofNullable(createCall(url, headerValues, Duration.ZERO).body(valueTypeRef));
}

private ResponseSpec createCall(String url, MultiValueMap<String, String> headerValues) {
public <T> Optional<T> restCall(String url, MultiValueMap<String, String> headerValues,
ParameterizedTypeReference<T> valueTypeRef, Duration delay) {
return Optional.ofNullable(createCall(url, headerValues, delay).body(valueTypeRef));
}

private ResponseSpec createCall(String url, MultiValueMap<String, String> headerValues, Duration delay) {
var myDelay = Optional.ofNullable(delay).orElse(Duration.ZERO);
if (!Duration.ZERO.equals(myDelay)) {
try {
LOGGER.info("Sleeping for {}", myDelay.toMillis());
Thread.sleep(myDelay);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
return this.restClient.get().uri(url).headers(headers -> headers.addAll(headerValues)).retrieve();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package ch.xxx.manager.adapter.client;

import java.time.Duration;
import java.util.List;
import java.util.Optional;

Expand All @@ -38,7 +39,7 @@ public Optional<List<HkSymbolImportDto>> importSymbols() {
LOGGER.info(myUrl);
var result = this.connectorClient.restCall(myUrl, new LinkedMultiValueMap<String, String>(),
new ParameterizedTypeReference<List<HkSymbolImportDto>>() {
});
}, Duration.ofMillis(100));
return result;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package ch.xxx.manager.adapter.client;

import java.time.Duration;
import java.util.List;
import java.util.Optional;

Expand Down Expand Up @@ -46,12 +47,12 @@ public void init() {
}

@Override
public Optional<RapidOverviewImportDto> importCompanyProfile(String symbol) {
public Optional<RapidOverviewImportDto> importCompanyProfile(String symbol, Duration delay) {
final String myUrl = String.format("https://yh-finance.p.rapidapi.com/stock/v2/get-profile?symbol=%s", symbol);
LOGGER.info(myUrl);
var headerMultiMap = new LinkedMultiValueMap<String, String>();
headerMultiMap.put("X-RapidAPI-Key", List.of(this.apiKey));
headerMultiMap.put("X-RapidAPI-Host", List.of("yh-finance.p.rapidapi.com"));
return this.connectorClient.restCall(myUrl, headerMultiMap, RapidOverviewImportDto.class);
return this.connectorClient.restCall(myUrl, headerMultiMap, RapidOverviewImportDto.class, delay);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
*/
package ch.xxx.manager.adapter.client;

import java.time.Duration;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
Expand All @@ -37,13 +38,13 @@ public XetraConnector(ConnectorClient connectorClient) {
@Override
public Optional<List<String>> importXetraSymbols() {
return this.connectorClient
.restCall(XETRA_URL, String.class).stream().map(str -> this.findCsvUrl(str)).findFirst()
.restCall(XETRA_URL, String.class, Duration.ofMillis(100)).stream().map(str -> this.findCsvUrl(str)).findFirst()
.flatMap(myUrlStr -> this.loadSymbolsCsv(myUrlStr));
}


private Optional<List<String>> loadSymbolsCsv(String url) {
return this.connectorClient.restCall(url, String.class).stream().map(str -> str.lines().toList()).findFirst();
return this.connectorClient.restCall(url, String.class, Duration.ofMillis(100)).stream().map(str -> str.lines().toList()).findFirst();
}

private String findCsvUrl(String htmlPage) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
package ch.xxx.manager.adapter.client;

import java.io.IOException;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.OffsetDateTime;
import java.util.List;
Expand Down Expand Up @@ -41,7 +42,7 @@ public YahooConnector(@Qualifier("csv") CsvMapper csvMapper, ConnectorClient con
}

@Override
public List<YahooDailyQuoteImportDto> getTimeseriesDailyHistory(String symbol) {
public List<YahooDailyQuoteImportDto> getTimeseriesDailyHistory(String symbol, Duration delay) {
LocalDateTime toTime = LocalDateTime.now();
LocalDateTime fromTime = LocalDateTime.of(2000, 1, 1, 0, 0);
final String myUrl = String.format(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ public Long importDailyQuoteHistory(String symbol, UserKeys userKeys) {
LOGGER.info("importQuoteHistory() called for symbol: {}", symbol);
return this.symbolRepository.findBySymbolSingle(symbol.toLowerCase()).stream()
.map(mySymbolEntity -> this.symbolRepository
.save(this.overviewImport(symbol, mySymbolEntity, Duration.ofSeconds(1L))))
.save(this.overviewImport(symbol, mySymbolEntity, Duration.ofMillis(200))))
.flatMap(symbolEntity -> Stream.of(
this.customImport(symbol, this.currencyService.getCurrencyMap(), symbolEntity, null, userKeys))
.flatMap(value -> Stream.of(this.saveAllDailyQuotes(value))))
Expand All @@ -90,7 +90,7 @@ private List<DailyQuote> customImport(String symbol, Map<LocalDate, Collection<C

public Long importUpdateDailyQuotes(String symbol, UserKeys userKeys) {
LOGGER.info("importNewDailyQuotes() called for symbol: {}", symbol);
return this.importUpdateDailyQuotes(Set.of(symbol), null, userKeys);
return this.importUpdateDailyQuotes(Set.of(symbol), Duration.ofMillis(100), userKeys);
}

public Long importUpdateDailyQuotes(String symbol, Duration delay, UserKeys userKeys) {
Expand Down Expand Up @@ -141,20 +141,11 @@ private List<DailyQuote> map(
}

private Symbol overviewImport(String symbol, Symbol symbolEntity, Duration delay) {
final Duration myDelay = Optional.ofNullable(delay).orElse(Duration.ZERO);
final Symbol mySymbolEntity = symbolEntity;
if (!Duration.ZERO.equals(myDelay)) {
try {
LOGGER.info("Sleeping for {}ms(2)", myDelay.toMillis());
Thread.sleep(myDelay);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
symbolEntity = switch (mySymbolEntity.getQuoteSource()) {
case ALPHAVANTAGE -> this.rapidApiClient.importCompanyProfile(symbol).stream()
case ALPHAVANTAGE -> this.rapidApiClient.importCompanyProfile(symbol, delay).stream()
.map(myDto -> this.updateSymbol(myDto, mySymbolEntity)).findFirst().orElse(mySymbolEntity);
case YAHOO -> this.rapidApiClient.importCompanyProfile(symbol).stream()
case YAHOO -> this.rapidApiClient.importCompanyProfile(symbol, delay).stream()
.map(myDto -> this.updateSymbol(myDto, mySymbolEntity)).findFirst().orElse(mySymbolEntity);
default -> Optional.of(mySymbolEntity).get();
};
Expand All @@ -178,28 +169,23 @@ private Symbol updateSymbol(RapidOverviewImportDto dto, Symbol symbol) {
}

private List<DailyQuote> yahooImport(String symbol, Map<LocalDate, Collection<Currency>> currencyMap,
Symbol symbolEntity, Duration delay) {
final Duration myDelay = Optional.ofNullable(delay).orElse(Duration.ZERO);
if (!Duration.ZERO.equals(myDelay)) {
try {
LOGGER.info("Sleeping for {}ms(1)", myDelay.toMillis());
Thread.sleep(myDelay);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
Symbol symbolEntity, Duration delay) {
return symbolEntity.getDailyQuotes() == null || symbolEntity.getDailyQuotes().isEmpty()
? this.yahooClient.getTimeseriesDailyHistory(symbol).stream()
? this.yahooClient.getTimeseriesDailyHistory(symbol, delay).stream()
.filter(QuoteImportService::filterEmptyValuesDto)
.map(importDtos -> this.convert(symbolEntity, importDtos, currencyMap)).toList()
: this.yahooClient.getTimeseriesDailyHistory(symbol).stream()
: this.yahooClient.getTimeseriesDailyHistory(symbol, delay).stream()
.filter(QuoteImportService::filterEmptyValuesDto)
.map(importDtos -> this.convert(symbolEntity, importDtos, currencyMap))
.filter(dto -> symbolEntity.getDailyQuotes().stream()
.noneMatch(myEntity -> myEntity.getLocalDay().isEqual(dto.getLocalDay())))
.filter(entity -> this.filterEntities(symbolEntity, entity))
.collect(Collectors.toList());
}

private boolean filterEntities(Symbol symbolEntity, DailyQuote dailyQuoteEntity) {
return symbolEntity.getDailyQuotes().stream()
.noneMatch(myEntity -> myEntity.getLocalDay().isEqual(dailyQuoteEntity.getLocalDay()));
}

private static boolean filterEmptyValuesDto(YahooDailyQuoteImportDto dto) {
return dto.getAdjClose() != null && dto.getVolume() != null;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
*/
package ch.xxx.manager.usecase.service;

import java.time.Duration;
import java.util.Optional;

import ch.xxx.manager.domain.model.dto.RapidOverviewImportDto;

public interface RapidApiClient {
Optional<RapidOverviewImportDto> importCompanyProfile(String symbol);
Optional<RapidOverviewImportDto> importCompanyProfile(String symbol, Duration delay);
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ public Future<Long> updateSymbolQuotes(List<Symbol> symbolsToUpdate) {
var myIndex = indexDaily.addAndGet(1L);
long userKeyIndex = Math.floorDiv(myIndex, PORTFOLIO_SYMBOL_LIMIT);
return Stream.of(this.quoteImportService.importUpdateDailyQuotes(mySymbol.getSymbol(),
Duration.ZERO, allUserKeys.get((Long.valueOf(userKeyIndex).intValue()))));
Duration.ofMillis(100), allUserKeys.get((Long.valueOf(userKeyIndex).intValue()))));
}).reduce(0L, (acc, value) -> acc + value);
LOGGER.info("Daily Quote import done for: {}", quoteCount);
LOGGER.info("updateSymbolQuotes done.");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,11 @@
*/
package ch.xxx.manager.usecase.service;

import java.time.Duration;
import java.util.List;

import ch.xxx.manager.domain.model.dto.YahooDailyQuoteImportDto;

public interface YahooClient {
List<YahooDailyQuoteImportDto> getTimeseriesDailyHistory(String symbol);
List<YahooDailyQuoteImportDto> getTimeseriesDailyHistory(String symbol, Duration delay);
}

0 comments on commit 05a528f

Please sign in to comment.