I have a webservice call to get an authorization token and use it for subsequent webservice calls. Now what we had done earlier was whenever we make any web service call, we first make the token web service and then make the call for actual web service.
Method to get the token is as shown below. Basically what this code does is call the webservice to get the token and using GSON parse the response and get the token.
public static String getAuthTicket() {
String authTicket = null;
HttpResponse httpResponse = getAuthResponse();
String body;
if (httpResponse.getStatusLine().getStatusCode() == 200) {
try {
body = IOUtils.toString(httpResponse.getEntity().getContent());
Gson gson = new GsonBuilder().disableHtmlEscaping().create();
ResponseTicket responseTicket = gson.fromJson(body, ResponseTicket.class);
authTicket = responseTicket.getTicket();
} catch (UnsupportedOperationException e) {
LOGGER.error("UnsupportedOperationException : ",e);
} catch (IOException e) {
LOGGER.error("IO Exception : ",e);
}
}
return authTicket;
}
This has obviously led to performance issue. Hence the party who is providing the webservice to get the token has made the token valid for 30 minutes.
So in the above method what we are thinking is to put the token in cache along with the time and check if the current time - cache time is less than 30. If time is greater than 30 we will make service call to get token and update the token with timestamp in cache.
The only thing is I am fearing is about synchronization, so that I dont get corrupt authtoken due to race condition.
I am thinking to make this static method as synchronized. Do you think is there any other better way.
The answer is: it depends.
Race conditions occur when more than one thread is accessing shared data at the same point in time. So, when you would have code such as:
private final Map<X, Y> sharedCache = new HashMap<>();
public static getAuthTicket() {
if (! sharedCache.containsKey...) {
sharedCache.put(...
...
You would be subject to a race conditions - two threads could come in at the same time, and update that shared map at the very same time; leading to all kinds of problems.
When I get your code right - you would have something similar:
private static String cachedToken = null;
public static getAuthTicket() {
if (cachedToken == null || isTooOld(cachedToken)) {
cachedToken = getAuthTicketForReal();
}
return cachedToken;
}
You probably do not want that two threads call getAuthTicketForReal() in parallel.
So, yes, making that method synchronized is a valid approach.
Where: the real question is: is it sufficient to add that keyword? Given my code - the answer is yes. You simply want to avoid that this cache is setup "in parallel" by more than one thread.
Finally: in case you are worried about the performance impact of using synchronized here - simply forget about that. You are talking about a multi-second "network based" operation; so you absolutely do not worry about the milli second of overhead that synchronized might have (making up this number - the key thing: it is so small that it doesn't matter in the context of the operation you are doing).
Regarding your comment: of course, using synchronized means that the JVM will serialize calls to that method. This means when this method needs 1 minute to return - any other calls to that method will block for that 1 minute.
In that sense; it might be a good exercise to look into ways of writing up this method in a way that does not require synchronized on method level. For example by using data structures that can deal with multiple threads manipulating them.
Related
I have this class containing AccessTokenWithExpirationDate object wrapped in AutomicReference which I want it to be thread safe:
public class MyClass {
private AtomicReference<AccessTokenWithExpirationDate> accessTokenWithExpirationDate = new AtomicReference<>();
private AccessTokenWithExpirationDate putAccessTokenToCache(AccessTokenDto accessTokenDto) {
AccessTokenWithExpirationDate currentValue = this.accessTokenWithExpirationDate.get();
AccessTokenWithExpirationDate accessTokenWithExpirationDate
= new AccessTokenWithExpirationDate(accessTokenDto);
// if currentValue the same, update.
// if currentValue not the same - another thread already updated it. continue.
this.accessTokenWithExpirationDate.compareAndSet(currentValue, accessTokenWithExpirationDate);
return accessTokenWithExpirationDate;
}
private Optional<String> getAccessTokenFromCache() {
Optional<AccessTokenWithExpirationDate> accessTokenWithExpirationDate = Optional.ofNullable(this.accessTokenWithExpirationDate.get());
if (accessTokenWithExpirationDate.isPresent() && isTokenNotExpired(accessTokenWithExpirationDate.get())) {
return accessTokenWithExpirationDate
.map(AccessTokenWithExpirationDate::getTokenDto)
.map(AccessTokenDto::getAccessToken);
} else {
return Optional.empty();
}
}
}
lets say AccessTokenWithExpirationDate has initial value and now Thread1 arrives to method putAccessTokenToCache and run: accessTokenWithExpirationDate.compareAndSet,
and at the same time other threads try to run:
accessTokenWithExpirationDate.get() in getAccessTokenFromCache method,
will all threads calling get() will wait for compareAndSet() to finish to get the value after or not guarantied ?
if not, can the class be changed in a way that will allow it? some other use in AutomicReference that can promise that?
thank you !
Atomic values don't allow blocking. In some cases, this is good, but in your case (if understand it correctly), it is not. As i understand it, you want to cache an access token. If it doesn't exist yet, or is expired, you want a new token to be created. Ultimately, you want any caller accessing the cache to get a valid token.
You can achieve this in a performant manner using (the valid form of) double checked locking.
The basic pattern is:
private volatile Token _currentToken;
public Token getValidToken() {
Token token = _currentToken;
if(!isValidToken(token)) {
token = loadToken();
}
return token;
}
private synchronized Token loadToken() {
Token token = _currentToken;
if(!isValidToken(token)) {
token = // ... get valid token here ...
_currentToken = token;
}
return token;
}
private boolean isValidToken(Token token) {
// .. validate that token is not null or expired ...
}
for callers who call getValidToken() when there is already a valid token, they won't encounter any locking. note that reading a volatile incurs a similar performance hit without actually blocking, but this about the best you can get for concurrent code (without doing something with ThreadLocal and potentially an access token per thread).
for callers who encounter a missing or expired token, they will all block until a single caller gets a new, valid token.
note, there are probably good cache implementations in either google guava or apache commons which would handle this logic for you.
lets say AccessTokenWithExpirationDate has initial value and now Thread1 arrives to method putAccessTokenToCache() and run: accessTokenWithExpirationDate.compareAndSet(...), and at the same time other threads try to run: accessTokenWithExpirationDate.get() in getAccessTokenFromCache method, will all threads calling get() will wait for compareAndSet() to finish to get the value after or not guaranteed ?
Whenever accessTokenWithExpirationDate.get() is called, the guarantee is that the most recently set value of accessTokenWithExpirationDate is returned. Period. There is no locking. If the get is called before the set then the old value is returned. If the get is called after the set then the new value is returned.
if not, can the class be changed in a way that will allow it? some other use in AutomicReference that can promise that?
You can certainly add locking but I'm not sure what it buys you. Either the other threads call get() before or after the set() has completed. If you added locking then the same race conditions would happen but you would make the getting and setting of the value a lot more expensive. In your case, each thread has to cross memory barriers to ensure the correct publishing of the accessTokenWithExpirationDate value but there is no blocking.
Full locking is necessary when there are multiple values being updated in an object or if you need to ensure a single thread is accessing a resource at a time. If you need to set a single value, in your case accessTokenWithExpirationDate, then an AtomicReference is the right tool for the job.
In my Spring Boot application I have a component that is supposed to monitor the health status of another, external system. This component also offers a public method that reactive chains can subscribe to in order to wait for the external system to be up.
#Component
public class ExternalHealthChecker {
private static final Logger LOG = LoggerFactory.getLogger(ExternalHealthChecker.class);
private final WebClient externalSystemWebClient = WebClient.builder().build(); // config omitted
private volatile boolean isUp = true;
private volatile CompletableFuture<String> completeWhenUp = new CompletableFuture<>();
#Scheduled(cron = "0/10 * * ? * *")
private void checkExternalSystemHealth() {
webClient.get() //
.uri("/health") //
.retrieve() //
.bodyToMono(Void.class) //
.doOnError(this::handleHealthCheckError) //
.doOnSuccess(nothing -> this.handleHealthCheckSuccess()) //
.subscribe(); //
}
private void handleHealthCheckError(final Throwable error) {
if (this.isUp) {
LOG.error("External System is now DOWN. Health check failed: {}.", error.getMessage());
}
this.isUp = false;
}
private void handleHealthCheckSuccess() {
// the status changed from down -> up, which has to complete the future that might be currently waited on
if (!this.isUp) {
LOG.warn("External System is now UP again.");
this.isUp = true;
this.completeWhenUp.complete("UP");
this.completeWhenUp = new CompletableFuture<>();
}
}
public Mono<String> waitForExternalSystemUPStatus() {
if (this.isUp) {
LOG.info("External System is already UP!");
return Mono.empty();
} else {
LOG.warn("External System is DOWN. Requesting process can now wait for UP status!");
return Mono.fromFuture(completeWhenUp);
}
}
}
The method waitForExternalSystemUPStatus is public and may be called from many, different threads. The idea behind this is to provide some of the reactive flux chains in the application a method of pausing their processing until the external system is up. These chains cannot process their elements when the external system is down.
someFlux
.doOnNext(record -> LOG.info("Next element")
.delayUntil(record -> externalHealthChecker.waitForExternalSystemUPStatus())
... // starting processing
The issue here is that I can't really wrap my head around which part of this code needs to be synchronised. I think there should not be an issue with multiple threads calling waitForExternalSystemUPStatusat the same time, as this method is not writing anything. So I feel like this method does not need to be synchronised. However, the method annotated with #Scheduled will also run on it's own thread and will in-fact write the value of isUp and also potentially change the reference of completeWhenUpto a new, uncompleted future instance. I have marked these two mutable attributes with volatilebecause from reading about this keyword in Java it feels to me like it would help with guaranteeing that the threads reading these two values see the latest value. However, I am unsure if I also need to add synchronized keywords to part of the code. I am also unsure if the synchronized keyword plays well with reactor code, I have a hard time finding information on this. Maybe there is also a way of providing the functionality of the ExternalHealthCheckerin a more complete, reactive way, but I cannot think of any.
I'd strongly advise against this approach. The problem with threaded code like this is it becomes immensely difficult to follow & reason about. I think you'd at least need to synchronise the parts of handleHealthCheckSuccess() and waitForExternalSystemUPStatus() that reference your completeWhenUp field otherwise you could have a race hazard on your hands (only one writes to it, but it might be read out-of-order after that write) - but there could well be something else I'm missing, and if so it may show as one of these annoying "one in a million" type bugs that's almost impossible to pin down.
There should be a much more reliable & simple way of achieving this though. Instead of using the Spring scheduler, I'd create a flux when your ExternalHealthChecker component is created as follows:
healthCheckStream = Flux.interval(Duration.ofMinutes(10))
.flatMap(i ->
webClient.get().uri("/health")
.retrieve()
.bodyToMono(String.class)
.map(s -> true)
.onErrorResume(e -> Mono.just(false)))
.cache(1);
...where healthCheckStream is a field of type Flux<Boolean>. (Note it doesn't need to be volatile, as you'll never replace it so cross-thread worries don't apply - it's the same stream that will be updated with different results every 10 minutes based on the healthcheck status, whatever thread you'll access it from.)
This essentially creates a stream of healthcheck response values every 10 minutes, always caches the latest response, and turns it into a hot source. This means that the "nothing happens until you subscribe" doesn't apply in this case - the flux will start executing immediately, and any new subscribers that come in on any thread will always get the latest result, be that a pass or a fail. handleHealthCheckSuccess() and handleHealthCheckError(), isUp, and completeWhenUp are then all redundant, they can go - and then your waitForExternalSystemUPStatus() can just become a single line:
return healthCheckStream.filter(x -> x).next();
...then job done, you can call that from anywhere and you'll have a Mono that will only complete when the system is up.
Here is a non Singleton class which is used to send a payload to an API...
class MyApiClient {
String url = "http://www.yankeeService.com"
int playerId = 99
String playerFirstName = "Aaron"
String playerLastName = "Judge"
public void sendPayload(String content) {
CloseableHttpClient client = HttpClients.createDefault();
HttpPost httpPost = new HttpPost();
String jsonPayload = """ "{"id":"$playerId","name":"$playerLastName","dailyReport":"$content"}" """ ;
StringEntity entity = new StringEntity(jsonPayload);
httpPost.setEntity(entity);
CloseableHttpResponse response = client.execute(httpPost);
assertThat(response.getStatusLine().getStatusCode(), equalTo(200));
client.close();
}
}
Would there be any problem if multiple threads were to enter that sendPayload method?
I think it would be fine because none of the global variables are modified in any way (they are read only and used to facilitate the API call).
Also the jsonPayload is a local variable so each thread would get their own version of it and there would be no chance for one thread to grab the payload content of another right?
Multi-threading issues come to play when threads are using and writing to shared data in an uncontrolled manner.
Meaning:
when all your threads are only invoking the send method, then you do not have a problem - because all threads are reading and using the same data
but when these threads change the content of any of the fields - then all bets are off.
And thing is: your fields have package visibility - this means it is very simple to update them from "outside". An object of MyApiClient would not even notice if field content is changed.
Thus:
first of all, make these fields private to hide such details from the outside
consider making them final as well
Yes it is thread safe. You are trying to post some thing to the remote location. It seems you are not worried about people overwriting the content at the remote location ( if you are then even thread safe logic will not be your help)
Your logic "I think it would be fine because none of the global variables are modified in any way (they are read only and used to facilitate the API call)."
is correct.
For readability and convention purpose I would suggest to use final construct with the attributes.
While there are multiple problems outside the scope of the question with the method you've proposed (what are """, do you really want to be crafting JSON objects by hand, and you don't handle exceptions) your assessment of concurrency appears to be correct.
You may want to ensure that, though, perhaps by making your variables final if they aren't supposed to ever be changed. This way if a future code modification does cause them to be changed, you'll know at compile time that there's a mistake. Or maybe it's not a mistake and those variables need to change... but you'll know you have to revisit your concurrency issue.
You can use http-request built on apache http api. Documentation here.
class MyApiClient {
private static final HttpRequest<?> HTTP_REQUEST =
HttpRequestBuilder.createGet("http://www.yankeeService.com")
.addContentType(ContentType.APPLICATION_JSON)
.build();
int playerId = 99
String playerFirstName = "Aaron"
String playerLastName = "Judge"
public void sendPayload(String content) {
String jsonPayload = """ "{"id":"$playerId","name":"$playerLastName","dailyReport":"$content"}" """ ;
assertThat(HTTP_REQUEST.executeWithBody(jsonPayload).getStatusCode(), equalTo(200));
}
}
HTTP_REQUEST is Thread Safe
I am fairly new to Java and extremely new to concurrency. However, I have worked with C# for a while. It doesn't really matter, but for the sake of example, I am trying to pull data off a table on server. I want method to wait until data is completely pulled. In C#, we have async-await pattern which can be used like this:
private async Task<List<ToDoItem>> PullItems ()
{
var newRemoteItems = await (from p in remoteTable select p).ToListAsync();
return newRemoteItems;
}
I am trying to have similar effect in Java. Here is the exact code I'm trying to port (Look inside SynchronizeAsync method.)! However, Java Azure SDK works with callbacks. So, I have a few options:
Use wait and notify pattern. Following code doesn't work since I don't understand what I'm doing.
final List<TEntity> newRemoteItems = new ArrayList<TEntity>();
synchronized( this ) {
remoteTable.where().field("lastSynchronized").gt(currentTimeStamp)
.execute(new TableQueryCallback<TEntity>() {
public void onCompleted(List<TEntity> result,
int count,
Exception exception,
ServiceFilterResponse response) {
if (exception == null) {
newRemoteItems.clear();
for (TEntity item: result) {
newRemoteItems.add(item);
}
}
}
});
}
this.wait();
//DO SOME OTHER STUFF
My other option is to move DO SOME OTHER STUFF right inside the callback's if(exception == null) block. However, this would result in my whole method logic chopped off into the pieces, disturbing the continuous flow. I don't really like this approach.
Now, here are questions:
What is recommended way of doing this? I am completing the tutorial on Java concurrency at Oracle. Still, clueless. Almost everywhere I read, it is recommended to use higher level stuff rather than wait and notify.
What is wrong with my wait and notify?
My implementation blocks the main thread and it's considered a bad practice. But what else can I do? I must wait for the server to respond! Also, doesn't C# await block the main thread? How is that not a bad thing?
Either put DO SOME OTHER STUFF into callback, or declare a semaphore, and call semaphore.release in the callback and call semaphore.aquire where you want to wait. Remove synchronized(this) and this.wait.
I am implementing REST through RESTlet. This is an amazing framework to build such a restful web service; it is easy to learn, its syntax is compact. However, usually, I found that when somebody/someprogram want to access some resource, it takes time to print/output the XML, I use JaxbRepresentation. Let's see my code:
#Override
#Get
public Representation toXml() throws IOException {
if (this.requireAuthentication) {
if (!this.app.authenticate(getRequest(), getResponse()))
{
return new EmptyRepresentation();
}
}
//check if the representation already tried to be requested before
//and therefore the data has been in cache
Object dataInCache = this.app.getCachedData().get(getURI);
if (dataInCache != null) {
System.out.println("Representing from Cache");
//this is warning. unless we can check that dataInCache is of type T, we can
//get rid of this warning
this.dataToBeRepresented = (T)dataInCache;
} else {
System.out.println("NOT IN CACHE");
this.dataToBeRepresented = whenDataIsNotInCache();
//automatically add data to cache
this.app.getCachedData().put(getURI, this.dataToBeRepresented, cached_duration);
}
//now represent it (if not previously execute the EmptyRepresentation)
JaxbRepresentation<T> jaxb = new JaxbRepresentation<T>(dataToBeRepresented);
jaxb.setFormattedOutput(true);
return jaxb;
}
AS you can see, and you might asked me; yes I am implementing Cache through Kitty-Cache. So, if some XML that is expensive to produce, and really looks like will never change for 7 decades, then I will use cache... I also use it for likely static data. Maximum time limit for a cache is an hour to remain in memory.
Even when I cache the output, sometimes, output are irresponsive, like hang, printed partially, and takes time before it prints the remaining document. The XML document is accessible through browser and also program, it used GET.
What are actually the problem? I humbly would like to know also the answer from RESTlet developer, if possible. Thanks