Commit dff641ad authored by wklicki's avatar wklicki

Enhance error handling in GusClientWithRateLimiter and refactor async...

Enhance error handling in GusClientWithRateLimiter and refactor async completion logic in GusSoapClient
parent 4bb6f42e
......@@ -40,20 +40,25 @@ public class GusClientWithRateLimiter {
}
private synchronized void refillTokensAndProcessQueue() {
long elapsedMillis = Instant.now().toEpochMilli() - lastRefillTime.toEpochMilli();
int refill = (int) (elapsedMillis * rateLimitPerSecond / 1000);
if (refill > 0) {
int current = tokens.get();
tokens.set(Math.min(rateLimitPerSecond, current + refill));
lastRefillTime = Instant.now();
}
// scheduleAtFixedRate silently stops rescheduling if this throws, so every
// path that can fail (a blocking GUS call) must be caught here.
try {
long elapsedMillis = Instant.now().toEpochMilli() - lastRefillTime.toEpochMilli();
int refill = (int) (elapsedMillis * rateLimitPerSecond / 1000);
if (refill > 0) {
int current = tokens.get();
tokens.set(Math.min(rateLimitPerSecond, current + refill));
lastRefillTime = Instant.now();
}
while (!requestQueue.isEmpty() && tokens.get() > 0) {
GusFuture<CompanyInfo> future = requestQueue.poll();
if (future != null && tokens.getAndDecrement() > 0) {
CompanyInfo ci = getInfo(future.getNip(), future.getKey());
workerPool.submit(() -> future.complete(ci));
while (!requestQueue.isEmpty() && tokens.get() > 0) {
GusFuture<CompanyInfo> future = requestQueue.poll();
if (future != null && tokens.getAndDecrement() > 0) {
completeAsync(future);
}
}
} catch (Exception e) {
logger.error("Error while refilling tokens / processing queue", e);
}
}
......@@ -61,9 +66,7 @@ public class GusClientWithRateLimiter {
synchronized (this) {
if (tokens.get() > 0) {
tokens.decrementAndGet();
CompanyInfo ci = getInfo(future.getNip(), future.getKey());
workerPool.submit(() -> future.complete(ci));
completeAsync(future);
return true;
} else {
return requestQueue.offer(future);
......@@ -71,6 +74,15 @@ public class GusClientWithRateLimiter {
}
}
private void completeAsync(GusFuture<CompanyInfo> future) {
try {
CompanyInfo ci = getInfo(future.getNip(), future.getKey());
workerPool.submit(() -> future.complete(ci));
} catch (Exception e) {
workerPool.submit(() -> future.completeExceptionally(e));
}
}
private CompanyInfo getInfo(String nip, String key) {
logger.info("Retrieving company info for nip: {}", nip);
soapClient.login(key);
......
......@@ -10,7 +10,6 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.annotation.RequestScope;
import org.springframework.ws.WebServiceMessage;
import org.springframework.ws.client.core.WebServiceMessageCallback;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
......@@ -22,7 +21,8 @@ import org.springframework.ws.transport.http.HttpUrlConnection;
import javax.xml.namespace.QName;
@RequestScope
// Singleton: mutable url/sessionId are safe only because GusClientWithRateLimiter
// serializes every call through it (synchronized) - never call this concurrently elsewhere.
@Component
public class GusSoapClient extends WebServiceGatewaySupport {
private static final Logger logger = LoggerFactory.getLogger(GusSoapClient.class);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment