JPA: pattern for handling OptimisticLockException - java

What is the correct pattern for handling OLE in a (REST) web service? this is what I'm doing now, for example,
protected void doDelete(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
...
...
...
try {
try {
em.getTransaction().begin();
// ... remove the entity
em.getTransaction().commit();
} catch (RollbackException e) {
if (e.getCause() instanceof OptimisticLockException) {
try {
CLog.e("optimistic lock exception, waiting to retry ...");
Thread.sleep(1000);
} catch (InterruptedException ex) {
}
doDelete(request, response);
return;
}
}
// ... write response
} catch (NoResultException e) {
response.sendError(HttpServletResponse.SC_NOT_FOUND, e.getMessage());
return;
} finally {
em.close();
}
}
anytime you see a sleep in the code, there's a good chance it's incorrect. Is there a better way to handle this?
another approach would be to immediately send the failure back to the client, but I'd rather not have them worry about it. the correct thing seems to do whatever is required to make the request succeed on the server, even if it takes a while.

If you get an optimistic locking exception, it means that some other transaction has committed changes to entities you were trying to update/delete. Since the other transaction has committed, retrying immediately might have a good chance to succeed.
I would also make the method fail after N attempts, rather than waiting for a StackOverflowException to happen.

The "politically correct" answer in rest, is to return an HTTP 409 (Conflict) witch matches perfectly with the idea of optimistic locking. Your client should manage it, probably by retring a few seconds later.
I wouldn't add the logic to retry in your app, as your client will already handle situations when you return a 40X code.

By the way, catch (InterruptedException e) {} is always a bad idea, because the system has asked your computation to cancel, and you are ignoring it. In the context of a web service, an InterruptedException would be another good reason to signal an error to the client.

If you're just going to keep retrying until it works anyway, why not just disable optimistic locking? You should let the caller know that they made a decision based on out dated information! If you're in control of both sides an appropriate 400 code can be returned. If it's public it can be more friendly to arbitrary clients to just return 500. (Of course then you perpetuate the under-use of appropriate response codes! such a dilemma)

Related

Retry in Camunda

I'm new to Camunda and I've been trying to get my head around the way it handles retries. Given the code below, is it possible to trigger a retry only when error_type_1 is caught?
} catch (error_type_1 e) {
log.error(e);
} catch (error_type_2 e) {
log.error(e);
you can add the retry and also retry after what time to your tasks initiator property
reference
Is this a code from your java delegate? In that case, you need to throw exception to trigger an incident.
I'm not sure what you are trying to achieve, but I can think of two options:
1) Rethrow a BpmnError, which will cause a business exception which you can handle in some error events. https://docs.camunda.org/javadoc/camunda-bpm-platform/7.3/org/camunda/bpm/engine/delegate/BpmnError.html
2) Implement custom IncidentHandler https://docs.camunda.org/manual/7.5/user-guide/process-engine/incidents/#implement-custom-incident-handlers

How to properly handle IOException for basicAck on RabbitMQ Channel when using Spring AMQP?

When having declared a method like this using Spring AMQP:
#RabbitListener(..)
public void myMethod(#Header(AmqpHeaders.CHANNEL) Channel channel, #Header(AmqpHeaders.DELIVERY_TAG) Long tag, ...)
and using manual acknowledge mode, how should one properly deal with the IOException that may be thrown when doing ACK:
try {
channel.basicAck(tag, false);
} catch (IOException e) {
// What to do here?
}
Should the exception be rethrown? Should the "basicAck" operation be retried? What's the proper way to handle it?
The standard way of doing this is using retry mechanism & to come out if none of them succeeds.
However, based on my experience, if channel throws an exception, it more or less means the channel is useless & you might have to redo the whole thing again. I normally log the error along with the required details so that I can track which message processing failed so that I can verify the same later to see if its processed or I need to do anything about it.

Handling different exceptions of the same type in Java?

When handling errors in Java it's common to see the superclasses being the errors that are caugh, such as
Exception, IOException, SocketException, etc.
However how do you go about finding the nitty-gritty details on the exception? How do you single a certain exception type out from the others. For instance, I'm currently working on a small project using Netty.io which throws an IOException for every type of read/write error you can name. This makes sense, because ultimately this is input/output errors, but how would I handle them individually.
Example exceptions:
java.io.IOException: An existing connection was forcibly closed by the remote host
java.io.IOException: Connection reset by peer
java.io.IOException: Stream closed
The list just continues to go on, but how would you go about handling these seperately, one approach that I've found while looking around and seems really nasty is the following.
try {
// ...
} catch (IOException e) {
if(e.getMessage().contains("An existing connection was forcibly closed by the remote host")) {
// Handle error
} else //...
}
This seems very tedious and there's bound to be a better way to do this, a correct way if you will. I've looked through quite a bit of error handling writeups over the last few hours and they all only talk about the big boys that are used commonly. IOException, Exception, SocketException, NullPointerException, and FileNotFoundException. Where I believe SocketException and FileNotFoundException would be directly related to the IOException, more than likely a subclass, correct me if I'm wrong.
Anyway, what's the proper way to go about handling these exceptions and how do you figure out exactly what kind of exception you need to be handling? All I can really do is handle IOException until something more precise comes up, but when developing applications it's always good to be able to handle each error uniquely.
In most of these cases the message is irrelevant from the point of view of your code. It's just something to be shown to the user, or logged. The only salient fact is that the connection is broken, for whatever reason, and there aren't different code paths you can use depending on which message it was.
The only one that's different is 'socket closed', which indicates a coding bug.
EDIT Regarding your comments below:
Any IOException other than SocketTimeoutException on a socket is fatal to the connection.
Invalid packets don't cause IOException: that's an application-layer problem that throws application-layer exceptions, or subclasses of IOException: e.g., java.io.StreamCorruptedException.
There is no such thing as IOException: connection closed by remote host. If the peer closes the connection, that causes an end-of-stream condition, which manifests itself as either read() returning -1, readLine() returning null, or readXXX() throwing EOFException for any other X.
I would suggest catching the exceptions in order, from most specific to least - such that you will notice a circuit break pattern when the exception you are looking for is reached. This is the best I can come up with:
try {
/// Something that can result in IOException or a SocketException
catch (IOException e){
//Do something specific
}catch (SocketExcpetion e){
}catch (Exception e) { //or some superclass of the above exceptions
///
}
Don't forget that you can also catch multiple exceptions of different types using the | command: catch (IOException|SocketException|
The documentation (http://docs.oracle.com/javase/7/docs/api/java/io/IOException.html) contains a long list of direct subclasses. You might want to look through them and check which ones you want to treat differently.
Once you know that, you can use multiple catch-blocks, first the subclasses, then the most general IOException:
catch(SSLException se) {
// do something
}
catch(HttpRetryException he) {
// do something else
}
catch(IOException ioe) {
// nop
}

Retrying an http connection

I'm making an http request. I'm on a platform (android) where network operations often fail because the network connection might not be immediately available. Therefore I'd like to try the same connection N times before completely failing. Was thinking of something like this:
DefaultHttpClient mHttp = ...;
public HttpResponse runHttpRequest(HttpRequestBase httpRequest)
throws IOException
{
IOException last = null;
for (int attempt = 0; attempt < 3; attempt++) {
try {
HttpResponse response = mHttpClient.execute(httpRequest);
int statusCode = response.getStatusLine().getStatusCode();
if (statusCode == 200) {
return response;
}
} catch (IOException e) {
httpRequest.abort();
last = e;
}
}
throw last;
}
I'm mostly worried about the connection being in some state which is invalid on subsequent retries. In other words, do I need to completely recreate 'httpRequest', should I avoid calling httpRequest.abort() in the catch block, and only call it in the final failure?
Thanks
The documentation does not mention that such a thing will occur, although you'd have to try it. More importantly, though, there are some things that you should consider with your code...
You should probably expose the number of retries, allowing the caller to specify this value.
You should only retry if an exception was thrown; you currently retry unless you get a 200. However if, for example, you get a 404... this doesn't mean your request failed in the sense that the network did not fail... rather, you made a successful round-trip to the server, but the server simply doesn't have the requested resource... so it really doesn't make sense to retry in such a case.
As-is, you might suppress all sorts of different types of exceptions. It might make sense to record all the exceptions that occurred in a List and return some sort of result object which contains the response (possibly null if all attempts failed) in addition to a list of all exceptions. Otherwise, you throw some arbitrary exception from the set of exceptions that occurred, possibly obscuring failure.
Right now you just hammer away with the same request, over and over again... if there is congestion, you are just adding to it. And if your IP address was banned for too much activity, you are probably going to be adding to that... any sort of retry logic should have a back-off behavior where there is some amount of waiting between retries and that interval increases with each failure.
A HttpRequestRetryHandler seems like it might be helpful here.
I'd recommend to use AOP and Java annotations from jcabi-aspects (I'm a developer):
#RetryOnFailure(attempts = 3, delay = 5)
public String load(URL url) {
return url.openConnection().getContent();
}

Why would I care about IOExceptions when a file is closed?

I've see this sort of thing in Java code quite often...
try
{
fileStream.close();
}
catch (IOException ioe)
{
/* Ignore. We do not care. */
}
Is this reasonable, or cavalier?
When would I care that closing a file failed? What are the implications of ignoring this exception?
I would at the very least log the exception.
I've seen it happen occasionally, if the attempt to close the file fails due to it not being able to flush the data. If you just swallow the exception, then you've lost data without realizing it.
Ideally, you should probably swallow the exception if you're already in the context of another exception (i.e. you're in a finally block, but due to another exception rather than having completed the try block) but throw it if your operation is otherwise successful. Unfortunately that's somewhat ugly to sort out :(
But yes, you should at least log it.
You would care if the close() method flushes written content from a buffer to the filesystem, and that fails. e.g. if the file you're writing to is on a remote filesystem that has become unavailable.
Note that the above re. flushing applies to any output stream, not just files.
The most common close() problems are out-of-disk space or, as Brian mentioned, a remote stream that's gone poof.
NOTE:
You should really see something like (note: I haven't compile-checked this)
SomeKindOfStream stream = null;
Throwable pending = null;
try {
stream = ...;
// do stuff with stream
} catch (ThreadDeath t) {
// always re-throw thread death immediately
throw t;
} catch (Throwable t) {
// keep track of any exception - we don't want an exception on
// close() to hide the exceptions we care about!
pending = t;
} finally {
if (stream != null)
try {
stream.close();
} catch (IOException e) {
if (pending == null)
pending = e;
}
}
if (pending != null) {
// possibly log - might log in a caller
throw new SomeWrapperException(pending);
// where SomeWrapperException is unchecked or declared thrown
}
}
Why all this?
Keep in mind that Java can only track one "pending" exception at a time. If the body of the main try block throws an exception, and the close() in the finally throws an exception, the only thing you'll know about is the close().
The above structure does the following:
Keep track of any throwable thrown in the body of the try
In case that exception is thread death, rethrow it immediately!
When closing, if we don't have a pending exception, track the close exception; otherwise the previously-thrown exception should be kept track of. (You should probably try to log the close() error in this case)
At the end, if there is a pending exception, deal with it. I usually wrap it and rethrow it. Personally, I use an unchecked wrapper so I don't need to have all callers in the call chain declare throws.
To do the above, I usually use the template method pattern to create the exception management and then override a doWork() method that is the body of the try.

Categories

Resources