Web Service Retry Java - java

I have a Java web app A that sends Pojo's to anothet web app B. I want to create a mechanism that retries the sending of the Pojos from A to B if B is down. The way B's api is configured in A is via Spring with B's jars in A's classpath. I have made a stab at it but the retry is not working. Can anyone tell me if I'm going in the right direction?
What is wrong here is that my code first executes, then rightly throws an exception. The exception is caught in the catch block. The catch block re-calls callB() which rightly throws an exception again but then my retry code goes into non source-file exception handling code and stops.
EDIT: I cannot use jcabi-aspects because it is not supported in Gradle.
public Object getB(Object request){
if (bClient != null) {
int retryCount = 0;
try {
return callB(request);
} catch (Exception e) {
if (++retryCount > 3) {
return null;
}
return callB(request);
}
}
return null;
}
private Object callB(Object request){
return bClient.callServiceB(request);
}

As you want code to repeatedly do something until it is successful, consider writing the control logic as a loop. You will find this makes it easy for you to change the number of retries before the code should give up.

Related

Handling CompletableFuture exceptions in controller

I'm trying to get into CompletableFuture class for a project I'm running, and I got to some question here:
There is the following method: it tries to find a conversation by its ID or hash; and, if not found, it throws an exception. So far, so good.
public ConversationOutput getConversationByIdOrHash(String conversationIdOrHash)
throws ConversationNotFoundException {
Conversation conversation = this.conversationRepository.getByIdOrHash(conversationIdOrHash);
if (conversation == null) {
throw new ConversationNotFoundException(conversationIdOrHash);
}
return this.modelMapper.map(conversation, ConversationOutput.class);
}
Note that I am throwing ConversationNotFoundException from my method signature. My SpringBoot controller is reacting to this exception and it's all working fine since the beginning.
What I'm trying to do is to make this to a CompletableFuture return and actually throwing an exception, something similar to:
public CompletableFuture<ConversationOutput> getConversationByIdOrHashAsync(String conversationIdOrHash)
throws ConversationNotFoundException {
return CompletableFuture.supplyAsync(() -> this.getConversationByIdOrHash(conversationIdOrHash));
}
I've seen posts where people use exceptionally to handle exceptions, but what I really want to do is to throw it to my controller and let it handle it. Any suggestions of how can I make it?
Thank you all!
The question is do you care about the result of CompletableFuture.
CompletableFuture is like a special task and it is processed on other thread. If you don't invoke .join() you won't receive the results of CompletableFuture. This method also will propagate the exception if any occured. However it waits for CompletableFuture to finish and blocks the request.
However, there is no way to get exceptions from the inside of the CompletableFuture without waiting, you have to treat it like other task.
You can pass the completed future in case of a success, and failed future along with your custom exception.
public CompletableFuture<ConversationOutput> getConversationByIdOrHashAsync(String conversationIdOrHash) {
try {
return CompletableFuture.completedFuture(this.getConversationByIdOrHash(conversationIdOrHash));
} catch (ConversationNotFoundException e) {
return CompletableFuture.failedFuture(e);
}
}
and then at your controller level you can handle the exception.
final CompletableFuture<ConversationOutput> future = getConversationByIdOrHashAsync("idOrHash");
future.whenComplete((r, e) -> {
if (e != null) {
if (e instanceof ConversationNotFoundException) {
//handling
}
}
});

why does the okhttp program dosen`t stucked in while(true)?

Recently i am reading the source code in OKHTTP and found that in RetryAndFollowUpInterceptor.java has a while(true) recycle. But, the program dose not stacked in that place or occur 'Application not responding'.Then I attached the debugger and put a breakpoint in that place and found it is running in main thread.I dont know why the program runs normal at all.Who can help me?
Thanks to stephenCs answer, but you might not get my point.In my question I mean why does the program not stuck in while(true) recycle in main thread.
For example, if there is a while(true) recycle in activity`s onCreate() lifecycle, the app might not run correctly ,just stuck in that place and can not respond touch event, which means the application not responding(ANR).
How will the recycle exit?
The following is the source code:
#Override
public Response intercept(Chain chain) throws IOException {
...
//This is the start of the recycle!Just recycle forever
while (true) {
if (canceled) {
streamAllocation.release();
throw new IOException("Canceled");
}
Response response;
boolean releaseConnection = true;
try {
response = realChain.proceed(request, streamAllocation, null, null);
releaseConnection = false;
} catch (RouteException e) {
// The attempt to connect via a route failed. The request will not have been sent.
if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
throw e.getFirstConnectException();
}
releaseConnection = false;
continue;
} catch (IOException e) {
// An attempt to communicate with a server failed. The request may have been sent.
boolean requestSendStarted = !(e instanceof ConnectionShutdownException);
if (!recover(e, streamAllocation, requestSendStarted, request)) throw e;
releaseConnection = false;
continue;
} finally {
// We're throwing an unchecked exception. Release any resources.
if (releaseConnection) {
streamAllocation.streamFailed(null);
streamAllocation.release();
}
...
}
}
}
If you are talking about this:
if (!recover(e.getLastConnectException(), streamAllocation, false, request)) {
throw e.getFirstConnectException();
}
releaseConnection = false;
continue;
or the similar code for IOException, the recover(...) call tests to see if failed request is recoverable. (See the method for what that actually means. But one of the criteria is that there is an alternative route that has not been tried yet.) If the call returns true, then the intercept method will retry. If it returns false then the relevant exception is rethrown.
In general, the logic in class is complicated, but it needs to be. And it clearly does work. So maybe you just need to read / study more of the context to understand what is happening.
Note that using a debugger to trace this could be difficult because the behavior is liable to change due to timeouts happening differently and altering the normal flow of control. Consider that possibility ...
UPDATE
How will the recycle exit?
It is called a loop, not a recycle.
As I have explained above, the particular loop paths that you highlighted will terminate (by rethrowing an exception) if the recover(...) call returns false. Let us take a look at recover.
private boolean recover(IOException e, boolean routeException, Request userRequest) {
streamAllocation.streamFailed(e);
// The application layer has forbidden retries.
if (!client.retryOnConnectionFailure()) return false;
// We can't send the request body again.
if (!routeException && userRequest.body() instanceof UnrepeatableRequestBody) return false;
// This exception is fatal.
if (!isRecoverable(e, routeException)) return false;
// No more routes to attempt.
if (!streamAllocation.hasMoreRoutes()) return false;
// For failure recovery, use the same route selector with a new connection.
return true;
}
The first statement is doing some cleanup on the StreamAllocation object. It isn't relevant to this.
The rest of the method is testing various things:
The application layers forbids retries, it says don't retry.
If a request was sent and it is not a resendable request, it says don't retry.
If the exception indicates an error that won't be fixed by retrying, it says don't retry.
If the route selector has no more routes to try, it says don't retry.
Otherwise it says retry. Next time that proceed is called, it will try the next route from the route selector.
Note that eventually it will run out of alternative routes to try.

Should I throw exceptions in an if-else block?

Here is the code:
public Response getABC(Request request) throws Exception {
Response res = new Response();
try {
if (request.someProperty == 1) {
// business logic
} else {
throw new Exception("xxxx");
}
} catch (Exception e) {
res.setMessage(e.getMessage); // I think this is weird
}
return res;
}
This program is working fine.
I think it should be redesigned, but how?
It makes no sense to throw an exception in a try block and immediately catch it, unless the catch block throws a different exception.
Your code would make more sense this way:
public Response getABC(Request request) {
Response res = new Response();
if (request.someProperty == 1) {
// business logic
} else {
res.setMessage("xxxx");
}
return res;
}
You only need the try-catch block if your business logic (executed when the condition is true) may throw exceptions.
If you don't catch the exception (which means the caller will have to handle it), you can do without the else clause:
public Response getABC(Request request) throws Exception {
if (request.someProperty != 1) {
throw new Exception("xxxx");
}
Response res = new Response();
// business logic
return res;
}
if you are throwing the exception from the method then why bother catching it ? it's either you return a response with "xxxx" message or throw an exception for the caller of this method to handle it.
public Response getABC(Request requst) {
Response res = new Response();
if(request.someProperty == 1){
//business logic
else{
res.setMessage("xxxx");
}
}
return res;
}
OR
public Response getABC(Request requst) throw Excetpions {
Response res = new Response();
if(request.someProperty == 1){
//business logic
else{
throw new Exception("xxxx");
}
return res;
}
public void someMethod(Request request) {
try {
Response r = getABC(request);
} catch (Exception e) {
//LOG exception or return response with error message
Response response = new Response();
response.setMessage("xxxx");
retunr response;
}
}
it doesn't seems right when purposely throwing exception and then directly catch it,
it can be redesign like this,
can change throw new Exception("xxxx"); with res.setMessage("xxxx");,
and then can keep the catching exception part in order to catch exception that may happen inside the business logic.
public Response getABC(Request requst) {
Response res = new Response();
try{
if(request.someProperty == 1){
//business logic
else{
res.setMessage("xxxx");
}
}catch(Exception e){
res.setMessage(e.getMessage);
}
return res;
}
First and foremost, tread more carefully when you refactor a working method - especially if you are performing a manual refactoring. That said, introducing a variable to hold message may be one way of changing the design:
public Response getABC(Request requst) throw Excetpions {
String message = "";
try{
if(request.someProperty == 1){
//business logic
else{
message = "xxxx";
}
}catch(Exception e){
message = e.getMessage();
}
Response res = new Response();
res.setMessage(message);
return res;
}
The assumption is that the business logic does it's own return when it succeeds.
I think you might be missing the point of that try/catch. The code is using the exception system to bubble any exception message to the caller. This could be deep inside a nested call stack--not just the one "throws" you are looking at.
In other words, the "throws" declaration in your example code is taking advantage of this mechanism to deliver a message to the client, but it almost certainly isn't the primary intended user of the try/catch. (Also it's a sloppy, kinda cheap way to deliver this message--it can lead to confusion)
This return value isn't a great idea anyway because Exceptions often don't have messages and can be re-wrapped... it's better than nothing though. Exception messages just aren't the best tool for this, but handling an exception at a high level like this is still a good idea.
My point is, if you refactor this code be sure to look for runtime exceptions that might be thrown anywhere in your code base (at least anywhere called during message processing)--and even then you should probably keep the catch/return message as a catch-all just in case a runtime exception pops up that you didn't expect. You don't have to return the error "Message" as the message of your response--It could be some quippy "We couldn't process your request at this time" instead, but be sure to dump the stack trace to a log. You are currently throwing it away.
Why did you use try/catch statement when you already throw Checked Exception?
Checked exception is usually used in some languages like C++ or Java, but not in new language like Kotlin. I personally restrict to use it.
For example, I have a class like this:
class ApiService{
Response getSomething() throw Exception();
}
which feels clean and readable, but undermines the utility of the exception handling mechanism. Practically, getSomething() doesn't offen throw checked exception but still need to behave as it does? This works when there is somebody upstream of ApiService who know how to deal with the unpredictable or unpreventable errors like this. And if you can really know how to deal with it, then go ahead and use something like the example below, otherwise, Unchecked Exception would be sufficient.
public Response getSomething(Request req) throws Exception{
if (req.someProperty == 1) {
Response res = new Response();
// logic
} else {
thows Exception("Some messages go here")
}
}
I will encourage to do in this way:
public Response getSomething(Request req){
if (req.someProperty == 1) {
Response res = new Response();
// logic
return res;
} else {
return ErrorResponse("error message"); // or throw RuntimeException here if you want to
}
}
For more insights, Kotlin which I mentioned before doesn't support Checked exception because of many reasons.
The following is an example interface of the JDK implemented by StringBuilder class:
Appendable append(CharSequence csq) throws IOException;
What does this signature say? It says that every time I append a string to something (a StringBuilder, some kind of a log, a console, etc.) I have to catch those IOExceptions. Why? Because it might be performing IO (Writer also implements Appendable)… So it results into this kind of code all over the place:
try {
log.append(message)
}
catch (IOException e) {
// Must be safe
}
And this is no good, see Effective Java, 3rd Edition, Item 77: Don't ignore exceptions.
Take a look at these links:
Checked and unchecked exception
Java's checked exceptions were a mistake (Rod Waldhoff)
The Trouble with Checked Exceptions (Anders Hejlsberg)
The exception mechanism has three purposes:
Immediately disable normal program flow and go back up the call stack until a suitable catch-block is found.
Provide context in form of the exception type, message and optionally additional fields that the catch-block code can use to determine course of action.
A stack trace for programmers to see to do forensic analysis. (This used to be very expensive to make).
This is a lot of functionality for a mechanism to have. In order to keep programs as simple as we can - for future maintainers - we should therefore only use this mechanism if we really have to.
In your example code I would expect any throw statement to be a very serious thing indicating that something is wrong and code is expected to handle this emergency somewhere. I would need to understand what went wrong and how severe it is before going on reading the rest of the program. Here it is just a fancy return of a String, and I would scratch my head and wonder "Why was this necessary?" and that extra effort could have been better spent.
So this code is not as good as it can be, but I would only change it if you had the time to do a full test too. Changing program flow can introduce subtle errors and you need to have the changes fresh in your mind if you need to fix anything.
Same if you want to get the specific exception message returned by JVM on failure, that time you can use the try-catch with methods getMessage() or printStackTrace() in the catch block. So here you can modify your code like :
public Response getABC(Request request) throws Exception {
Response res = new Response();
try {
if (request.someProperty == 1) {
// business logic
}
} catch (Exception e) {
res.setMessage(e.getMessage);
}
return res;
}

Is it possible to monitor handled exceptions using JUnit?

This is what I have:
#Test
public testSendMessageToStub() {
// under the hood sends message
// if exception occurrs
// it will be catched and message will be put on retry
object.sendMessage();
}
Is there any way to mark test as failed if exception has occurred but was handled in catch block in the sendMessage() method?
Thanks
EDIT: It seems like I was too fixated on these legacy tests and how they were used, that totally missed the fact of sendMessage returning a response with a status code (!!!). So now I just assert status codes, can expand these tests into more detailed scenarios and spin them on jenkins. I would like to avoid to answer how these tests were checked previously. The thought to check for status codes came to me after reading Plux's answer. Thanks!
Exactly what you are looking for is not possible with JUnit as far as I know.
If you really would want to test this, you could store some information about the exception in the catch-block where it is handled in the sendMessage() method.
A better option, in my opinion, could be to test the output or state of the object. If the state/output is exactly the same as when an exception doesn't occur, then whats the point of testing it? Do you have an overly broad catch-block?
EDIT: To AdityaTS, I dont have enough reputation to comment on a post, but my comment: you have not supplied all the code, so I can not say for sure, but my guess is that its the Logger.getLogger IN the catch-block that casts the ClassNotFoundException. (Either that or loadConnectionInfo()) see http://docs.oracle.com/javase/7/docs/api/java/lang/ClassNotFoundException.html
You cannot do this without modifying sendMessage method. If for example you catch the exception there but choose to ignore it and just return some value, code outside of the method doesn't know it. You can get around this by refactoring the code of object: move the code that handles the exception to a separate method, called e.g. handleException. Then, in your test you can create a subclass where handleException will execute the original handleException from superclass, but additionally set some flag which you will be able to read in your test and in this way tell that the exception was thrown. However, if you cannot modify the code for object's class, I'm afraid you're out of luck.
So you expect the exception to propagate out of the sendMessage() method, right?
This is another way to write a test that verifies an exception you expect will be thrown.
#Test (expected = MyExpectedException.class)
public testSendMessageToStub() {
// under the hood sends message
// if exception occurrs
// it will be catched and message will be put on retry
object.sendMessage();
}
And it's usually best to be as specific as possible (e.g. MyExpectedException.class over Exception.class)
The exception generated in the sendMessage() class will be available in the test method. Add a try catch block around the sendMessage() method like this
#Test
public testSendMessageToStub() {
try
{
object.sendMehssage();
}
catch(Excpetion e) //Use more specific exception type if you know
{
fail(e.getMessage());
}
}
I have tried this in my code. It worked for me. Let me know.
public DBConnectionInfo connectionInit()
{
loadConnectionInfo();
try
{
Class.forName(dbObject.getDriver());
} catch (Exception e)
{
Logger lgr = Logger.getLogger(PostgreLocationManager.class.getName());
lgr.log(Level.SEVERE, e.getMessage(), e);
}
try
{
dbObject.setConnection(DriverManager.getConnection(dbObject.getDatabaseURL(), dbObject.getUserName(),
dbObject.getPassword()));
} catch (Exception e)
{
Logger lgr = Logger.getLogger(PostgreLocationManager.class.getName());
lgr.log(Level.SEVERE, e.getMessage(), e);
}
return dbObject;
}
The test case for the above class.
#Test
public void testDriverFailure()
{
when(dbModelObject.getDriver()).thenReturn("driver");
when(dbModelObject.getDatabaseURL()).thenReturn("jdbc:postgresql://127.0.0.1:5432/testdb");
when(dbModelObject.getUserName()).thenReturn("postgres");
when(dbModelObject.getPassword()).thenReturn("postgres");
try
{
dbConnector.connectionInit();
} catch (Exception e)
{
assertTrue(e instanceof ClassNotFoundException);
}
verify(dbModelObject).getDriver();
}

PlayFramework: catch a deadlock and reissue transaction

I am running a Play! application and am debugging a deadlock.
The error messages I see logged from Play! are:
Deadlock found when trying to get lock; try restarting transaction
Could not synchronize database state with session
org.hibernate.exception.LockAcquisitionException: Could not execute JDBC batch update
From the Play! Documentation
Play will automatically manage transactions for you. It will start a transaction for each HTTP request and commit it when the HTTP response is sent. If your code throws an exception, the transaction will automatically rollback.
From the MySQL Documentation
you must write your applications so that they are always prepared to re-issue a transaction if it gets rolled back because of a deadlock.
My question:
How and where in my Play! application can I catch these rolled back transactions, and handle them (choose to reissue them, ignore them, etc...)?
Updated
While I ended up taking the advice in the accepted answer, and looking for the cause of the deadlock (did you know MySQL foreign key constraints increase the chance of deadlocking? Now I do!), here is some code that was working for me to catch and reissue a failed save.
boolean success = false;
int tries = 0;
while (!success && tries++ < 3) {
try {
updated.save();
success = true;
} catch (javax.persistence.PersistenceException e) {
pause(250);
}
}
You can use custom Enhancer and enhance all controllers in your plugin.
For example, enhancer add catch block and restart request invocation. It is more reliable for restart request then only part of logic inside controller:
package plugins;
..
final public class ReliableTxPlugin extends PlayPlugin {
public void enhance(final ApplicationClasses.ApplicationClass applicationClass) throws Exception {
new TxEnhancer().enhanceThisClass(applicationClass);
}
}
package enhancers;
..
class TxEnhancer extends Enhancer {
public static void process(PersistenceException e) throws PersistenceException {
final Throwable cause = e.getCause();
if (cause instanceof OptimisticLockException || cause instanceof StaleStateException) {
final EntityTransaction tx = JPA.em().getTransaction();
if (tx.isActive()) {
tx.setRollbackOnly();
}
Http.Request.current().isNew = false;
throw new Invoker.Suspend(250);
}
throw e;
}
public void enhanceThisClass(final ApplicationClass applicationClass) throws Exception {
// .. general encahcer code
ctMethod.addCatch("enhancers.TxEnhancer.process(_e);return;",
classPool.makeClass("javax.persistence.PersistenceException"), "_e");
//..
}
}
In most cases of a deadlock you can only do a rollback and try a restart. How ever in a Webapp this should be a really unusual case. What you can do in Play is
catch the exception
handle the Transaction in your code
With JPA.em() you will get the EntityManager. You can look into JPAPlugin to see how play handle the transaction. How ever first of all I would evaluate why there is a deadlock and if this is really a realistic situation which can the server handle intelligent.
I built a play1 module based on #xedon work doing the retry for you.

Categories