We are trying to put Spring Cloud Netflix into production environment. For now we encounter a problem about business logic error handling.
We're using Feign as HTTP REST client. Microservice A needs to invoke microservice B which is deployed in different JVM(or physical server). Microservice B may return some error message which belongs to business. For instance A needs to query order information from B but the order ID may not exist so B has to return the error message that tells A this order doesn't exist. A has to do if-else judgement from the return message to determine if there are erorrs, then code will be like the following snippet:
//remoteServiceA is an interface annotated with #FeignClient
resultA = remoteServiceA.foo();
if (resultA.hasError) {
} else {
}
resultB = remoteServiceB.foo();
if (resultB.hasError) {
} else {
}
// ... ...
There are so many if-else so that it's not graceful enough. What we want is remoteServieA.foo() can throw a self-defined runtime exception such as OrderNotExistException. Any idea to achieve this goal?
I've solved this problem.
I customized the ErrorDecoder component of Feign, in which I can throw my own exception according to the HTTP original response.
If you have Hystrix enabled, you should be able to wrap you serviceA.foo() in a try block and throw an exception in your remote service.
try {
serviceA.foo();
} catch(HystrixRuntimeException ex) {
throw new OrderNotExistException("Error message");
}
You still have to take in account that you can catch that kind of exception if your remote service doesn't answer, or if an other error happens. Maybe you can find information the exception about what happened and decide if you should throw your exception.
First thing that comes to my mind but work in one of my project.
Related
I have a verticle which accepts REST request, get data from other verticle through event bus and respond back to client.
vertx.exceptionHandler(event -> logger.error("Vertx exception ", event));
router.get("/api/v1/:param").handler(this::routerHandler);
public void routerHandler(RoutingContext rc) {
vertx.eventBus().request("data", param,
result -> {
if (result.succeeded()) {
logger.info("Request handled successfully");
// intentionally creating exception body() will return String
JsonObject jsonObject = (JsonObject) result.result().body();
rc.response().end(jsonObject)
}else{
logger.error("Request failed");
}
}
When a exception is raised it is printed in exception handler that I setup in vertx instance but after that the vertx is not reporting back the exception immediately to client instead it waits for timeout(30 secs) to occur.
I tried attaching error handler to router object and failure handler to route object but nothing helps to report the exception immediately to client. I know I can have a try catch and report the error in catch block. But I want know if there is any other way to handle this like Servlet or Spring MVC reports back to client even though the exception is not handled in code.
router.errorHandler(500,routingContext -> {
System.out.println(routingContext.failed());
routingContext.response().end("Exception ");
});
router.route().handler(BodyHandler.create()).failureHandler(routingContext -> {
Uncaught exceptions are reported to the context exceptionHandler. By default it prints the exception to the console.
You can configure it but you will not get a reference to the corresponding HTTP request anyway (the exception may come from different things).
Most problems like this are usually found during unit/integration/acceptance testing.
And for the remainders you could set a timeout handler on your router definition to make sure the request is ended before the default 30 seconds.
If you don't want to miss any uncaught exception, you should switch to the Vert.x Rxified API. When using RxJava, any exception thrown will be reported to the subscriber.
While running test (with Citrus or not) an exception may occurs if the test expects a message on a queue but the message isn't received before the timeout expires.
In this case I'd like know which line throws the Exception.
Unfortunatelly citrus doesn't show this information.
Here's my code :
#Test
#CitrusTest
public void testFail() {
sequential().actions(
mycheckNoError1(),
mycheckNoError2(),
mycheckNoError3(), //this one fails , we want to know it and which line throws the ActionTimeoutException
mycheckNoError4()
);
}
protected AbstractActionContainer mycheckNoError3() {
AbstractActionContainer aCatch = catchException().exception(ActionTimeoutException.class)
.when(receive("for_soap_q")
.timeout(100L)
.validationCallback(validationCallbackFunc()
))
.addTestAction(timeoutException(Thread.currentThread().getStackTrace()));
return aCatch;
}
And here's the stacktrace of citrus, that doesn't show the line that throws the exception:
...
INFO .c.r.LoggingReporter|
ERROR .c.r.LoggingReporter| TEST FAILED MyTest.test <package.test> Nested exception is:
com.consol.citrus.exceptions.ActionTimeoutException: Action timed out while receiving JMS message on 'testQueue'
at com.consol.citrus.jms.endpoint.JmsConsumer.receive(JmsConsumer.java:95) ~[citrus-jms-2.7.5.jar:na]
at com.consol.citrus.jms.endpoint.JmsConsumer.receive(JmsConsumer.java:60) ~[citrus-jms-2.7.5.jar:na]
at com.consol.citrus.jms.endpoint.JmsSyncConsumer.receive(JmsSyncConsumer.java:60) ~[citrus-jms-2.7.5.jar:na]
...
The only way I found was to pass the stacktrace as parameter of a method timeoutException() I wrote:
private TestAction timeoutException(StackTraceElement[] methodName) {
System.out.println("++++++++++ timeout Exception at line " + methodName[1].getLineNumber() + " in method: [" + methodName[1].getMethodName() + "]");
return null;
}
But I guess there is a better way to do this.
Is there a way to configure properly citrus and/or override the LoggingReporter to show the line number that make the exception happen ?
(in this case, this is the line: when(receive("for_soap_q")...)
thanks.
You can overwrite the default Logging reporter by placing a bean named 'loggingReporter' in the Spring application context. In addition to that you can add custom reporters and test listeners when choosing different bean naming. Just add the custom listeners to the Spring application context and they will get test events and throwable errors for reporting.
Also make sure to use the TestRunner fluent API instead of the TestDesigner fluent API. Designer is slightly more straight forward but runner will execute the test actions immediately while building the test case with the fluent API. So you will get more detailed stack traces with correct line numbers and the ability to set breakpoints for better debugging.
I'm trying to read a Cookie value in my server side implementation class. After some debugging my code now looks like this:
logger.info("Initiating login");
String oracleDad;
try {
logger.info("inside try");
oracleDad = Cookies.getCookie("dad");
logger.info("Read dad from cookie: " + oracleDad);
} catch (Exception e) {
logger.error("Failed to read dad from cookie", e);
oracleDad = "gtmd";
}
When I execute this code my onFailure block is fired with a Status code Exception:
com.google.gwt.user.client.rpc.StatusCodeException: 500 The call
failed on the server; see server log for details
My logging output on the server looks like this:
[INFO] c.g.e.server.rpc.MyProjectImpl - Initiating login
[INFO] c.g.e.server.rpc.MyProjectImpl - inside try
How is it possible that neither logger, the INFO or the ERROR, fire after the Cookies.getCookie() call? I'd hoped that by adding the catch(Exception e) I'd get some error message explaining why the code fails. But execution just seems to stop silently.
I'm using com.google.gwt.user.client.Cookies. I thought client code can be run on the server, just not vice versa. Is that correct? Is there something else I'm missing?
I'm using com.google.gwt.user.client.Cookies. I thought client code can be run on the server, just not vice versa. Is that correct? Is there something else I'm missing?
No, that's not correct, yes there is something you are missing: Server code can't run on the client, and client code can't run on the server.
You are not getting an Exception. You are getting an Error or some other Throwable.
Try catching Throwable in your try/catch block, and you'll see that you are getting an error where the server JVM is unable to load the Cookies class, because something is wrong. The JVM thinks that a native library is missing (because it doesn't know what JSNI is or how to run it), so it throws an UnsatisfiedLinkError:
Thrown if the Java Virtual Machine cannot find an appropriate native-language definition of a method declared native.
In GWT, the Cookies class is meant to interact with the browser itself to see what cookies have been defined on the currently loaded page. To use cookies on a J2EE server, ask the HttpServletRequest object for the cookies it knows about, and their values.
Using JAX-WS 2, I see an issue that others have spoken about as well. The issue is that if a SOAP message is received inside a handler, and that SOAP message is large - whether due to inline SOAP body elements that happen to have lots of content, or due to MTOM attachments - then it is dangerously easy to get an OutOfMemoryError.
The reason is that the call to getMessage() seems to set off a chain of events that involve reading the entire SOAP message on the wire, and creating an object (or objects) representing what was on the wire.
For example:
...
public boolean handleMessage(SOAPMessageContext context)
{
// for a large message, this will cause an OutOfMemoryError
System.out.println( context.getMessage().countAttachments() );
...
My question is: is there a known mechanism/workaround for dealing with this? Specifically, it would be nice to access the SOAP part in a SOAP message without forcing the attachments (if MTOM for example) to also be vacuumed up.
For those who run their app on JBoss 6 & 7 (with Apache CXF)... I was able to troubleshoot the problem by implementing my handler from the LogicalHandler interface instead of the SOAPHandler.
In this case your handleMessage() method would get the LogicalMessageContext context (instead of SOAPMessageContext) in the arguments that has no issues with the context.getMessage() call
There's actually a JAX-WS RI (aka Metro) specific solution for this which is very effective.
See https://javaee.github.io/metro/doc/user-guide/ch02.html#efficient-handlers-in-jax-ws-ri. Unfortunately that link is now broken but you can find it on WayBack Machine. I'll give the highlights below:
The Metro folks back in 2007 introduced an additional handler type, MessageHandler<MessageHandlerContext>, which is proprietary to Metro. It is far more efficient than SOAPHandler<SOAPMessageContext> as it doesn't try to do in-memory DOM representation.
Here's the crucial text from the original blog article:
MessageHandler:
Utilizing the extensible Handler framework provided by JAX-WS
Specification and the better Message abstraction in RI, we introduced
a new handler called MessageHandler to extend your Web Service
applications. MessageHandler is similar to SOAPHandler, except that
implementations of it gets access to MessageHandlerContext (an
extension of MessageContext). Through MessageHandlerContext one can
access the Message and process it using the Message API. As I put in
the title of the blog, this handler lets you work on Message, which
provides efficient ways to access/process the message not just a DOM
based message. The programming model of the handlers is same and the
Message handlers can be mixed with standard Logical and SOAP handlers.
I have added a sample in JAX-WS RI 2.1.3 showing the use of
MessageHandler to log messages and here is a snippet from the sample:
public class LoggingHandler implements MessageHandler<MessageHandlerContext> {
public boolean handleMessage(MessageHandlerContext mhc) {
Message m = mhc.getMessage().copy();
XMLStreamWriter writer = XMLStreamWriterFactory.create(System.out);
try {
m.writeTo(writer);
} catch (XMLStreamException e) {
e.printStackTrace();
return false;
}
return true;
}
public boolean handleFault(MessageHandlerContext mhc) {
.....
return true;
}
public void close(MessageContext messageContext) { }
public Set getHeaders() {
return null;
}
}
(end quote from 2007 blog post)
You can find a full example in the Metro GitHub repo.
What JAX-WS implementation runtime are you using? If there's a way to do this using the runtime built into WebSphere I'm certain there's a way to do this cleanly in other runtimes like Axis2 (proper), Apache CXF, and Metro/RI.
I am using the other way to reduce the memory costing, which is Message Accessor.
Instead of using context.getMessage(), I changed it to this way:
Object accessor = context.get("jaxws.message.accessor");
if (accessor != null) {
baosInString = accessor.toString();
}
Base on advice from IBM website. http://www-01.ibm.com/support/docview.wss?uid=swg1PM21151
I have a C# service that runs continuously with user credentials (i.e not as localsystem - I can't change this though I want to). For the most part the service seems to run ok, but ever so often it bombs out and restarts for no apparent reason (servicer manager is set to restart service on crash).
I am doing substantial event logging, and I have a layered approach to Exception handling that I believe makes at least some sort of sense:
Essentially I got the top level generic exception, null exception and startup exception handlers.
Then I got various handlers at the "command level" (i.e specific actions that the service runs)
Finally I handle a few exceptions handled at the class level
I have been looking at whether any resources aren't properly released, and I am starting to suspect my mailing code (send email). I noticed that I was not calling Dispose for the MailMessage object, and I have now rewritten the SendMail code as illustrated below.
The basic question is:
will this code properly release all resources used to send mails?
I don't see a way to dispose of the SmtpClient object?
(for the record: I am not using object initializer to make the sample easier to read)
private static void SendMail(string subject, string html)
{
try
{
using ( var m = new MailMessage() )
{
m.From = new MailAddress("service#company.com");
m.To.Add("user#company.com");
m.Priority = MailPriority.Normal;
m.IsBodyHtml = true;
m.Subject = subject;
m.Body = html;
var smtp = new SmtpClient("mailhost");
smtp.Send(m);
}
}
catch (Exception ex)
{
throw new MyMailException("Mail error.", ex);
}
}
I know this question is pre .Net 4 but version 4 now supports a Dispose method that properly sends a quit to the smpt server. See the msdn reference and a newer stackoverflow question.
There are documented issues with the SmtpClient class. I recommend buying a third party control since they aren't too expensive. Chilkat makes a decent one.