-
1. Re: Rollback for DB call with transport-level error
walkerca Jan 16, 2018 2:04 PM (in response to nickarls)1 of 1 people found this helpfulHi,
If I were in this situation, I'd involve JMS and an Asynchronous EJB to implement fire-and-forget (rather than request-response). Of course, there are a bunch of ramifications to this approach. You'd need to communicate errors back using another JMS queue or put a record in a table that could be polled later for reconciliation. If the clients time out a lot, you could be having a negative impact on them, causing a backup down the line while everyone is synchronously waiting on you.
However, here's a hack that seems to work. Try streaming your HTTP response. At least on WildFly, this gave me "preparing output" if I waited for the results in a browser and a "Connection gone; rollback" if I hit the stop button 3 seconds into the operation.
@Path("/hw")
public class HelloWorldResource {
@GET
@Produces(MediaType.TEXT_PLAIN)
@Path("/hwStreamed")
public Response streamedHW() {
StreamingOutput stream = os -> {
try {
Thread.sleep(10_000); // kill me in the browser
} catch(InterruptedException exc) {
exc.printStackTrace();
}
try {
Writer writer = new BufferedWriter(new OutputStreamWriter(os));
writer.write("Hello, World! (Streamed)");
writer.flush();
writer.close();
System.out.println("preparing output");
} catch(Exception exc) {
System.err.println("Connection gone; rollback");
}
};
return Response.ok().entity( stream ).build();
}
}
-
2. Re: Rollback for DB call with transport-level error
nickarls Jan 16, 2018 5:09 PM (in response to walkerca)Yes, it is semantically a bit tricky because
a) separate messages can also be lost/delayed
b) the service is happy when it completes it's work (response is written), and has completed by the time the response might actually be read (and an error occurs)
Your approach is certainly worth looking into (having control of the response long enough to retain control for the service). Another approach we are looking into is having the client re-transmit the message in case of an IO-error and having the message return the old response (side-effect free) since all messages have an unique ID which could be tracked to see if the actual work has already been done
-
3. Re: Rollback for DB call with transport-level error
walkerca Jan 16, 2018 6:28 PM (in response to nickarls)I've done the re-transmits before and ended up replacing that for a JMS approach. If you're expecting heavy traffic, this can present problems. When your system is under stress, that mechanism can lead to a DDOS that you can't get out from under. As you start bogging down, the clients get more timeouts. So, they send more messages. Your processing gets slower...
-
4. Re: Rollback for DB call with transport-level error
nickarls Jan 17, 2018 1:38 AM (in response to walkerca)An additional complication is that we have others integrating to the system (in some cases Oracle DB:s doing the REST calls) so it's non-trivial for them to implement the JMS
-
5. Re: Rollback for DB call with transport-level error
jaikiran Jan 17, 2018 1:45 AM (in response to nickarls)1 of 1 people found this helpfulBased on what you note, you probably won't need JMS for this and the Async servlet support introduced in Servlet 3.0 should probably be an option in this case Asynchronous Support in Servlet 3.0 | Oracle Enterprise Tech Tips Blog
-
6. Re: Rollback for DB call with transport-level error
nickarls Jan 17, 2018 2:04 AM (in response to jaikiran)Thanks, I'll look into it. The problem is not that much that the actual message processing would be long-running - the problem is that if there is a network error when reading the response the client has no way if the receipt lost was an "ok" or an "error"...
-
7. Re: Rollback for DB call with transport-level error
walkerca Jan 17, 2018 7:44 AM (in response to nickarls)Hi,
I'd definitely keep the REST interface if that wasn't clear. The solution I have in mind would be a REST resource paired with an EJB method optionally with @Asynchronous. The EJB method would put the payload -- probably JSON coming from the REST call -- on the JMS queue.
I might do some light validation in the REST resource, basically anything RAM based like a required field check unless the parsing was too intensive. Then you can return the synchronous 400 error if there's a problem right out of the gate.
Finally, for development and testing by the external clients, I would allow a flag (ex "validateOnly=true") to be passed in. This would skip the EJB call for the queue but run the payload through the full complement of validations available downstream.
Good luck
-
8. Re: Rollback for DB call with transport-level error
walkerca Jan 17, 2018 7:45 AM (in response to jaikiran)I still like to be able to tap into and inject messages into the queue for processing. I've had good luck with the EJB @Asynchronous though.