vertx timeout if async result is failed - vert.x

I am seeing a timeout in the browser when the server-side service ends in a failed result. Everything works fine if the service call succeeds but it seems as though the browser never receives a response if the call fails.
My service passes a result handler to a DAO containing the following code:
final SQLConnection conn = ar.result();
conn.updateWithParams(INSERT_SQL, params, insertAsyncResult -> {
if (insertAsyncResult.failed()) {
conn.close();
resultHandler.handle(ServiceException.fail(1, "TODO"));
} else {
resultHandler.handle(Future.succeededFuture());
}
});
I'm not sure where to go from here. How do I debug what the framework is sending back to the client?

The problem was that I needed to register a ServiceExceptionMessageCodec in an intermediate Verticle, one that was sitting between the browser and the Verticle that was performing the database operation.

Related

WebClient hanging when using share() followed by block() call but calling block() only returns with an error

I am using the Spring WebFlux WebClient in a spring batch application and I am getting an error when I call block. The code is really simple but I am getting an error when the application I try launching a job from a Rest endpoint on a controller in the batch job.
The rest endpoint is like this:
#RequestMapping("/migration/products/catalog
class ProductController{
private final Job job;
ResponseEntity<Map<String,Object> loadProductCatalog(){
// Code to launch Product Catalog Job
}
}
Here is the method the calls a remote client to get Product Catalog information that can be used by the Controller to load information about products
public ProductInfo findProductInfo() {
try{
String url =....;
return webClient.get().uri(url)
.accept(MediaType.APPLICATION_JSON).retrieve().
bodyToMono(ProductInfo.class).share().block();
}catch(Exception e){
log.error("Exception during retrieval of ProductInfo Data [}", e);
return null;
}
}
The findProductInfo method is wrapped in a Service which is used to retrieve ProductInfo in the Controller.
I am using share() because the block() call to the Rest controller just hangs.
However, if I simply call block() with first calling share() the call to the controller returns but throws the following error. I'm very new to using WebFlux so I have no idea what is going on. I'd appreciate some help in deciphering what is going on and a solution to this problem
java.lang.IllegalStateException: block()/blockFirst()/blockLast() are blocking, which is not supported in thread reactor-http-nio-2
When I use share() followed by block() my application hangs when I invoke the rest endpoint. However, if I use block() alone the method returns
Solved: My job was running in a single thread, so the share().block() was blocking the main thread of the job launcher. I figured out that from observing the task executor was synchronous and that gave me the clue, it suddenly made sense. I configured a task executor so the job would run in its own thread and viola!

Vertx not able to handle internal code error to client automatically

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.

Response not submitted when rxEnd is used in HTTP server

I have a two verticle server written in vert.x + reactive extensions. HTTP server verticle uses event bus to send requests to the DB verticle. After receiving the response from the DB verticle (through event bus) I send the response to the http client using rxEnd. However clients does not seem to receive this response and times out eventually. If I were to use end() instead, things work fine. I use postman to test this REST API. Please see below for the code which forward results from the DB verticle to client.
routerFactory.addHandlerByOperationId("createChargePoints", routingContext -> {
RequestParameters params = routingContext.get("parsedParameters");
RequestParameter body = params.body();
JsonObject jsonBody = body.getJsonObject();
vertx.eventBus().rxRequest("dbin", jsonBody)
.map(message -> {
System.out.println(message.body());
return routingContext.response().setStatusCode(200).rxEnd(message.body().toString());
})
.subscribe(res -> {
System.out.println(res);
}, res -> {
System.out.println(res);
});
});
The rxEnd method is a variant of end that returns a Completable. The former is lazy, the latter is not.
In other words, if you invoke rxEnd you have to subscribe to the Completable otherwise nothing happens.
Looking at the code of your snippet, I don't believe using rxEnd is necessary. Indeed, it doesn't seem like you need to know if the request was sent succesfully.

Why does my API call not return when everything is synchronous?

I have a Vue.js application on the frontend and a Node.js REST API on the backend (on AWS).
I was making a call to the backend from the front end and getting a 504 error (gateway timeout) and I couldn't figure out why. Then I copied the code from an almost identical pattern elsewhere in the application and it worked. I don't know why it worked. I'm hoping that someone can explain to me why my code didn't work and why the code I copied does work.
First you need to know what my code looks like. So here it is:
FRONTEND:
async saveTimestamp() {
try {
await api.post(`blahBlahEndpoint`);
this.flag = false;
} catch (err) {
console.log('err=', err);
}
}
BACKEND:
RequestHandler:
require('./blahBlahController').setSomething(params);
return new HttpResponse(204);
Controller:
setSomething(params) {
this.dao.setSomething(params);
}
DAO:
setSomething(params) {
this.db.runQuery('blah blah query with params');
}
So essentially, the front end sends a post request to the backend. The endpoint is our RequestHandler, and once it figures out the right controller and method for the job, it requires the controller and calls the method, passing it any parameters that came with the request. The controller in turn calls a method on the DAO passing the parameters along. The method on the DAO (setSomething(...)) injects the parameters into a query string which gets passed to db.runQuery(...). db.runQuery is from a third party library. It essentially runs the query against our database (in my case, doing a simple field update). It's asynchronous and therefore returns a promise. As you can see, I'm ignoring the promise and just returning right away (I don't need the results of the query so I just let it do its thing and carry on). So other than runQuery(...), everything is synchronous. Why then does my frontend call timeout? After about a minute of waiting, the catch block catches a 504 error, which google tells me is a timeout error.
Now let's look at the fix:
FRONTEND:
async saveTimestamp() {
try {
await api.post(`blahBlahEndpoint`);
this.flag = false;
} catch (err) {
console.log('err=', err);
}
}
BACKEND:
RequestHandler:
await require('./blahBlahController').setSomething(params);
return new HttpResponse(204);
Controller:
async setSomething(params) {
await this.dao.setSomething(params);
}
DAO:
async setSomething(params) {
await this.db.runQuery('blah blah query with params');
}
Very simple. I just converted everything on the backend to async/await. But why does this fix the problem. I'm obviously not understanding how the async/await pattern handles promises and/or how that changes the dynamic between frontend and backend (at least with REST APIs).
Here's some assumptions I'm making that may be false:
1) Without the async/await pattern (where the bug existed), all method calls from the RequestHandler to the DAO only return when the method is done, and they return nothing (with the exception of the RequestHandler which returns a HttpResponse with a 204 status to the front end).
2) Because runQuery is asynchronous, it returns a promise, and it returns it immediately (i.e. before it is done).
3) Since DAO.setSomething(...) does not await the call to runQuery, it carries on as soon as it's done calling runQuery. The promise returned from runQuery is dropped. While runQuery does its thing (updating the DB), the API begins the return portion of its round trip, returning nothing.
4) RequestHandler finally returns an HttpResponse object to the frontend. At the frontend, this object becomes the object of the Promise being awaited, effectively resolving the promise and permitting the API call to stop awaiting.
^ 4) is what doesn't seem to happen. All backend logs indicate that everything works just as I describe above, right up to the point of returning the HttpResponse, and the updates to the database corroborate this. This tells me there is an issue with how my code above (pre-fix) effects the way by which the backend returns to the frontend, but what exactly?
Here's what I imagine is happening with the fix:
1) No changes to frontend. Frontend makes call to backend like before.
2) In RequestHandler, call to setSomething(...) in controller is made asynchronously, which means it returns a promise right away and is awaited.
3) In Controller's setSomething(...), call to DAO.setSomething(...) is made. Since this is asynchronous, it returns a promise right away and is awaited.
4) In DAO.setSomething(...), call to runQuery(...) is made. Since runQuery(...) is asynchronous, it returns a promise right away and is awaited.
5) Once the promise returned from runQuery(...) is resolved (because runQuery(...) finishes), DAO.setSomething(...) returns.
6) The promise returned from DAO.setSomething(...) is resolved by DAO.setSomething(...) returning, and it stops awaiting. This causes Controller.setSomething(...) to return.
7) The promise returned from Controller.setSomething(...) is resolved by Controller.setSomething(...) returning, and RequestHandler stops awaiting.
8) RequestHandler returns the HttpResponse object to the frontend with status 204.
9) The promise returned from the api call is resolved by way of the HttpResponse object being returned. The promise resolves into the HttpResponse object. The frontend stop awaiting and continues on.
^ Hopefully, this gives a detailed account of what my understanding is surrounding frontend requests and backend responses, and what happens when promises and async/await patterns are involved. Does anyone care to correct any misunderstandings I have? Anything that would explain why the frontend wasn't getting a response in the pre-fix state?
Thanks very much for any forthcoming responses.

how does Netty server know when client is disconnected?

I am making Netty Server that satisfies the following conditions:
Server needs to do transaction process A, when it receives packet from its client.
After finishing transaction, if it is still connected, it sends back return message to client. If not, do some rollback process B.
But my problem is that when I send back to client, the Server does not know wheter it is still connected or not.
I've tried following codes to figure out its connection before sending messages. However it always succeeds even though client already closed its socket. It only fails when client process is forcibly killed (e.g. Ctrl+C)
final ChannelFuture cf = inboundChannel.writeAndFlush(resCodec);
cf.addListener(new ChannelFutureListener() {
#Override
public void operationComplete(ChannelFuture future) {
if (future.isSuccess()) {
inboundChannel.close();
} else {
try {
// do Rollback Process B Here
}
}
});
I thought this is because of TCP protocol. If client disconnect gracefully, then FIN signal is sent to server. So it does think writeAndFlush succeeds somehow even when it doesn't.
So I've tried following code too, but these have the same result (always return true)
if(inboundChannel.isActive()){
inboundChannel.writeAndFlush(msg);
} else{
// do RollBack B
}
// Similar codes using inboundChannel.isOpen(), inboundChannel.isWritable()
Neither 'channelInactive' event nor 'Connection Reset by Peer' exception occur in my case.
This is the part of Netty test client code that I used.
public void channelActive(ChannelHandlerContext ctx) {
ctx.writeAndFlush(message).addListener(ChannelFutureListener.CLOSE);
}
How can I notice disconnection at the time that I want to reply?
May be you should override the below method and see if the control goes here when channel is closed.
#Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
// write cleanup code
}
I don't think its possible to track that whether client is connected or not in netty because there is an abstraction between netty and client.