PriceFeedService.requestAllPrices() cycles providers and updates cache
This commit is contained in:
parent
ad17228b38
commit
fb1b8f8bd8
@ -80,10 +80,14 @@ public class ProvidersRepository {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public void selectNextProviderBaseUrl() {
|
// returns true if provider selection loops to beginning
|
||||||
|
public boolean selectNextProviderBaseUrl() {
|
||||||
|
boolean looped = false;
|
||||||
if (!providerList.isEmpty()) {
|
if (!providerList.isEmpty()) {
|
||||||
if (index >= providerList.size())
|
if (index >= providerList.size()) {
|
||||||
index = 0;
|
index = 0;
|
||||||
|
looped = true;
|
||||||
|
}
|
||||||
|
|
||||||
baseUrl = providerList.get(index);
|
baseUrl = providerList.get(index);
|
||||||
index++;
|
index++;
|
||||||
@ -95,6 +99,7 @@ public class ProvidersRepository {
|
|||||||
log.warn("We do not have any providers. That can be if all providers are filtered or providersFromProgramArgs is set but empty. " +
|
log.warn("We do not have any providers. That can be if all providers are filtered or providersFromProgramArgs is set but empty. " +
|
||||||
"bannedNodes={}. providersFromProgramArgs={}", bannedNodes, providersFromProgramArgs);
|
"bannedNodes={}. providersFromProgramArgs={}", bannedNodes, providersFromProgramArgs);
|
||||||
}
|
}
|
||||||
|
return looped;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void fillProviderList() {
|
private void fillProviderList() {
|
||||||
|
@ -22,16 +22,15 @@ import bisq.core.locale.TradeCurrency;
|
|||||||
import bisq.core.monetary.Price;
|
import bisq.core.monetary.Price;
|
||||||
import bisq.core.provider.PriceHttpClient;
|
import bisq.core.provider.PriceHttpClient;
|
||||||
import bisq.core.provider.ProvidersRepository;
|
import bisq.core.provider.ProvidersRepository;
|
||||||
|
import bisq.core.trade.HavenoUtils;
|
||||||
import bisq.core.trade.statistics.TradeStatistics3;
|
import bisq.core.trade.statistics.TradeStatistics3;
|
||||||
import bisq.core.user.Preferences;
|
import bisq.core.user.Preferences;
|
||||||
|
|
||||||
import bisq.network.http.HttpClient;
|
import bisq.network.http.HttpClient;
|
||||||
|
|
||||||
import bisq.common.Timer;
|
import bisq.common.Timer;
|
||||||
import bisq.common.UserThread;
|
import bisq.common.UserThread;
|
||||||
import bisq.common.handlers.FaultHandler;
|
import bisq.common.handlers.FaultHandler;
|
||||||
import bisq.common.util.MathUtils;
|
import bisq.common.util.MathUtils;
|
||||||
import bisq.common.util.Tuple2;
|
|
||||||
|
|
||||||
import com.google.inject.Inject;
|
import com.google.inject.Inject;
|
||||||
|
|
||||||
@ -45,6 +44,7 @@ import javafx.beans.property.ReadOnlyIntegerProperty;
|
|||||||
import javafx.beans.property.SimpleIntegerProperty;
|
import javafx.beans.property.SimpleIntegerProperty;
|
||||||
import javafx.beans.property.SimpleStringProperty;
|
import javafx.beans.property.SimpleStringProperty;
|
||||||
import javafx.beans.property.StringProperty;
|
import javafx.beans.property.StringProperty;
|
||||||
|
import javafx.beans.value.ChangeListener;
|
||||||
|
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
|
||||||
@ -57,8 +57,8 @@ import java.util.Map;
|
|||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.concurrent.CancellationException;
|
import java.util.concurrent.CancellationException;
|
||||||
|
import java.util.concurrent.CountDownLatch;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
import java.util.concurrent.TimeoutException;
|
import java.util.concurrent.TimeoutException;
|
||||||
import java.util.function.Consumer;
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
@ -88,14 +88,16 @@ public class PriceFeedService {
|
|||||||
private final StringProperty currencyCodeProperty = new SimpleStringProperty();
|
private final StringProperty currencyCodeProperty = new SimpleStringProperty();
|
||||||
private final IntegerProperty updateCounter = new SimpleIntegerProperty(0);
|
private final IntegerProperty updateCounter = new SimpleIntegerProperty(0);
|
||||||
private long epochInMillisAtLastRequest;
|
private long epochInMillisAtLastRequest;
|
||||||
private long retryDelay = 1;
|
private long retryDelay = 0;
|
||||||
private long requestTs;
|
private long requestTs;
|
||||||
|
private long lastLoopTs = System.currentTimeMillis();
|
||||||
@Nullable
|
@Nullable
|
||||||
private String baseUrlOfRespondingProvider;
|
private String baseUrlOfRespondingProvider;
|
||||||
@Nullable
|
@Nullable
|
||||||
private Timer requestTimer;
|
private Timer requestTimer;
|
||||||
@Nullable
|
@Nullable
|
||||||
private PriceRequest priceRequest;
|
private PriceRequest priceRequest;
|
||||||
|
private String requestAllPricesError = null;
|
||||||
|
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -236,25 +238,33 @@ public class PriceFeedService {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void retryWithNewProvider() {
|
private void retryWithNewProvider() {
|
||||||
// We increase retry delay each time until we reach PERIOD_SEC to not exceed requests.
|
long thisRetryDelay = 0;
|
||||||
UserThread.runAfter(() -> {
|
|
||||||
retryDelay = Math.min(retryDelay + 5, PERIOD_SEC);
|
|
||||||
|
|
||||||
String oldBaseUrl = priceProvider.getBaseUrl();
|
String oldBaseUrl = priceProvider.getBaseUrl();
|
||||||
setNewPriceProvider();
|
boolean looped = setNewPriceProvider();
|
||||||
|
if (looped) {
|
||||||
|
if (System.currentTimeMillis() - lastLoopTs < PERIOD_SEC * 1000) {
|
||||||
|
retryDelay = Math.min(retryDelay + 5, PERIOD_SEC);
|
||||||
|
} else {
|
||||||
|
retryDelay = 0;
|
||||||
|
}
|
||||||
|
lastLoopTs = System.currentTimeMillis();
|
||||||
|
thisRetryDelay = retryDelay;
|
||||||
|
}
|
||||||
log.warn("We received an error at the request from provider {}. " +
|
log.warn("We received an error at the request from provider {}. " +
|
||||||
"We select the new provider {} and use that for a new request. retryDelay was {} sec.", oldBaseUrl, priceProvider.getBaseUrl(), retryDelay);
|
"We select the new provider {} and use that for a new request in {} sec.", oldBaseUrl, priceProvider.getBaseUrl(), thisRetryDelay);
|
||||||
|
UserThread.runAfter(() -> {
|
||||||
request(true);
|
request(true);
|
||||||
}, retryDelay);
|
}, thisRetryDelay);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void setNewPriceProvider() {
|
// returns true if provider selection loops back to beginning
|
||||||
providersRepository.selectNextProviderBaseUrl();
|
private boolean setNewPriceProvider() {
|
||||||
|
boolean looped = providersRepository.selectNextProviderBaseUrl();
|
||||||
if (!providersRepository.getBaseUrl().isEmpty())
|
if (!providersRepository.getBaseUrl().isEmpty())
|
||||||
priceProvider = new PriceProvider(httpClient, providersRepository.getBaseUrl());
|
priceProvider = new PriceProvider(httpClient, providersRepository.getBaseUrl());
|
||||||
else
|
else
|
||||||
log.warn("We cannot create a new priceProvider because new base url is empty.");
|
log.warn("We cannot create a new priceProvider because new base url is empty.");
|
||||||
|
return looped;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Nullable
|
@Nullable
|
||||||
@ -333,12 +343,25 @@ public class PriceFeedService {
|
|||||||
/**
|
/**
|
||||||
* Returns prices for all available currencies.
|
* Returns prices for all available currencies.
|
||||||
* For crypto currencies the value is XMR price for 1 unit of given crypto currency (e.g. 1 DOGE = X XMR).
|
* For crypto currencies the value is XMR price for 1 unit of given crypto currency (e.g. 1 DOGE = X XMR).
|
||||||
* For fiat currencies the value is price in the given fiiat currency per 1 XMR (e.g. 1 XMR = X USD).
|
* For fiat currencies the value is price in the given fiat currency per 1 XMR (e.g. 1 XMR = X USD).
|
||||||
* Does not update PriceFeedService internal state (cache, epochInMillisAtLastRequest)
|
*
|
||||||
|
* TODO: instrument requestPrices() result and fault handlers instead of using CountDownLatch and timeout
|
||||||
*/
|
*/
|
||||||
public Map<String, MarketPrice> requestAllPrices() throws ExecutionException, InterruptedException, TimeoutException, CancellationException {
|
public synchronized Map<String, MarketPrice> requestAllPrices() throws ExecutionException, InterruptedException, TimeoutException, CancellationException {
|
||||||
return new PriceRequest().requestAllPrices(priceProvider)
|
CountDownLatch latch = new CountDownLatch(1);
|
||||||
.get(20, TimeUnit.SECONDS);
|
ChangeListener<? super Number> listener = (observable, oldValue, newValue) -> { latch.countDown(); };
|
||||||
|
updateCounter.addListener(listener);
|
||||||
|
requestAllPricesError = null;
|
||||||
|
requestPrices();
|
||||||
|
UserThread.runAfter(() -> {
|
||||||
|
if (latch.getCount() == 0) return;
|
||||||
|
requestAllPricesError = "Timeout fetching market prices within 20 seconds";
|
||||||
|
latch.countDown();
|
||||||
|
}, 20);
|
||||||
|
HavenoUtils.awaitLatch(latch);
|
||||||
|
updateCounter.removeListener(listener);
|
||||||
|
if (requestAllPricesError != null) throw new RuntimeException(requestAllPricesError);
|
||||||
|
return cache;
|
||||||
}
|
}
|
||||||
|
|
||||||
///////////////////////////////////////////////////////////////////////////////////////////
|
///////////////////////////////////////////////////////////////////////////////////////////
|
||||||
@ -350,6 +373,7 @@ public class PriceFeedService {
|
|||||||
String errorMessage = null;
|
String errorMessage = null;
|
||||||
if (currencyCode != null) {
|
if (currencyCode != null) {
|
||||||
String baseUrl = priceProvider.getBaseUrl();
|
String baseUrl = priceProvider.getBaseUrl();
|
||||||
|
httpClient.setBaseUrl(baseUrl);
|
||||||
if (cache.containsKey(currencyCode)) {
|
if (cache.containsKey(currencyCode)) {
|
||||||
try {
|
try {
|
||||||
MarketPrice marketPrice = cache.get(currencyCode);
|
MarketPrice marketPrice = cache.get(currencyCode);
|
||||||
|
@ -17,7 +17,6 @@
|
|||||||
|
|
||||||
package bisq.core.provider.price;
|
package bisq.core.provider.price;
|
||||||
|
|
||||||
import bisq.core.locale.CurrencyUtil;
|
|
||||||
import bisq.core.provider.HttpClientProvider;
|
import bisq.core.provider.HttpClientProvider;
|
||||||
|
|
||||||
import bisq.network.http.HttpClient;
|
import bisq.network.http.HttpClient;
|
||||||
@ -25,7 +24,6 @@ import bisq.network.p2p.P2PService;
|
|||||||
|
|
||||||
import bisq.common.app.Version;
|
import bisq.common.app.Version;
|
||||||
import bisq.common.util.MathUtils;
|
import bisq.common.util.MathUtils;
|
||||||
import bisq.common.util.Tuple2;
|
|
||||||
|
|
||||||
import com.google.gson.Gson;
|
import com.google.gson.Gson;
|
||||||
import com.google.gson.internal.LinkedTreeMap;
|
import com.google.gson.internal.LinkedTreeMap;
|
||||||
|
Loading…
Reference in New Issue
Block a user