How can I tread OpenDolphin client send HttpHostConnectException? - client-server

Is there way to handle situation when message is not delivered to server? Dolphin log infors about situation clearly, but I'would like to catch it from code. I was looking for some method like: onError to override like onFinished:
clientDolphin.send(message, new OnFinishedHandlerAdapter() {
#Override
public void onFinished(List<ClientPresentationModel> presentationModels) {
// Do something useful
}
}
});
, but there is nothing like that. Also wrapping send call in try/catch does not work(not suprising since send is not blocking its caller code).
I thing there is definitely some easy way to get informed about undelivered message, but I cant see it.
Thaks, in advace, for answers!

You can assign an onException handler to the ClientConnector - and you are actually supposed to do so. The exception handler will get the exception object passed in that happened in the asynchronous send action.
Below is the default handler that even tells you, what you should do ;-)
Closure onException = { Throwable up ->
def out = new StringWriter()
up.printStackTrace(new PrintWriter(out))
log.severe("onException reached, rethrowing in UI Thread, consider setting ClientConnector.onException\n${out.buffer}")
uiThreadHandler.executeInsideUiThread { throw up } // not sure whether this is a good default
}

Related

How to tell RSocket to read data stream by Java 8 Stream which backed by Blocking queue

I have the following scenario whereby my program is using blocking queue to process message asynchronously. There are multiple RSocket clients who wish to receive this message. My design is such a way that when a message arrives in the blocking queue, the stream that binds to the Flux will emit. I have tried to implement this requirement as below, but the client doesn't receive any response. However, I could see Stream supplier getting triggered correctly.
Can someone pls help.
#MessageMapping("addListenerHook")
public Flux<QueryResult> addListenerHook(String clientName){
System.out.println("Adding Listener:"+clientName);
BlockingQueue<QueryResult> listenerQ = new LinkedBlockingQueue<>();
Datalistener.register(clientName,listenerQ);
return Flux.fromStream(
()-> Stream.generate(()->streamValue(listenerQ))).map(q->{
System.out.println("I got an event : "+q.getResult());
return q;
});
}
private QueryResult streamValue(BlockingQueue<QueryResult> inStream){
try{
return inStream.take();
}catch(Exception e){
return null;
}
}
This is tough to solve simply and cleanly because of the blocking API. I think this is why there aren't simple bridge APIs here to help you implement this. You should come up with a clean solution to turn the BlockingQueue into a Flux first. Then the spring-boot part becomes a non-event.
This is why the correct solution is probably involving a custom BlockingQueue implementation like ObservableQueue in https://www.nurkiewicz.com/2015/07/consuming-javautilconcurrentblockingque.html
A alternative approach is in How can I create reactor Flux from a blocking queue?
If you need to retain the LinkedBlockingQueue, a starting solution might be something like the following.
val f = flux<String> {
val listenerQ = LinkedBlockingQueue<QueryResult>()
Datalistener.register(clientName,listenerQ);
while (true) {
send(bq.take())
}
}.subscribeOn(Schedulers.elastic())
With an API like flux you should definitely avoid any side effects before the subscribe, so don't register your listener until inside the body of the method. But you will need to improve this example to handle cancellation, or however you cancel the listener and interrupt the thread doing the take.

Mono returned by ServerRequest.bodyToMono() method not extracting the body if I return ServerResponse immediately

I am using web reactive in spring web flux. I have implemented a Handler function for POST request. I want the server to return immediately. So, I have implemeted the handler as below -:
public class Sample implements HandlerFunction<ServerResponse>{
public Mono<ServerResponse> handle(ServerRequest request) {
Mono bodyMono = request.bodyToMono(String.class);
bodyMono.map(str -> {
System.out.println("body got is " + str);
return str;
}).subscribe();
return ServerResponse.status(HttpStatus.CREATED).build();
}
}
But the print statement inside the map function is not getting called. It means the body is not getting extracted.
If I do not return the response immediately and use
return bodyMono.then(ServerResponse.status(HttpStatus.CREATED).build())
then the map function is getting called.
So, how can I do processing on my request body in the background?
Please help.
EDIT
I tried using flux.share() like below -:
Flux<String> bodyFlux = request.bodyToMono(String.class).flux().share();
Flux<String> processFlux = bodyFlux.map(str -> {
System.out.println("body got is");
try{
Thread.sleep(1000);
}catch (Exception ex){
}
return str;
});
processFlux.subscribeOn(Schedulers.elastic()).subscribe();
return bodyFlux.then(ServerResponse.status(HttpStatus.CREATED).build());
In the above code, sometimes the map function is getting called and sometimes not.
As you've found, you can't just arbitrarily subscribe() to the Mono returned by bodyToMono(), since in that case the body simply doesn't get passed into the Mono for processing. (You can verify this by putting a single() call in that Mono, it'll throw an exception since no element will be emitted.)
So, how can I do processing on my request body in the background?
If you really still want to just use reactor to do a long task in the background while returning immediately, you can do something like:
return request.bodyToMono(String.class).doOnNext(str -> {
Mono.just(str).publishOn(Schedulers.elastic()).subscribe(s -> {
System.out.println("proc start!");
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("proc end!");
});
}).then(ServerResponse.status(HttpStatus.CREATED).build());
This approach immediately publishes the emitted element to a new Mono, set to publish on an elastic scheduler, that is then subscribed in the background. However, it's kind of ugly, and it's not really what reactor is designed to do. You may be misunderstanding the idea behind reactor / reactive programming here:
It's not written with the idea of "returning a quick result and then doing stuff in the background" - that's generally the purpose of a work queue, often implemented with something like RabbitMQ or Kafka. It's "raison d'ĂȘtre" is instead to be non-blocking, so a single thread is never idly blocked, waiting for something else to complete.
The map() method isn't designed for side effects, it's designed to transform each object into another. For side effects, you want doOnNext() instead;
Reactor uses a single thread by default, so your "additional processing" in your map() method would still block that thread.
If your application is for anything more than quick demo purposes, and/or you need to make heavy use of this pattern, then I'd seriously consider setting up a proper work queue instead.
This is not possible.
Web servers (including Reactor Netty, Tomcat, etc) clean up and recycle resources when request processing is done. This means that when your controller handler is done, the HTTP resources, the request itself, reusable buffers, etc are recycled or closed. At that point, you cannot read from the request body anymore.
In your case, you need to read and buffer the whole request body first, then return a response and kick off a task for processing that request in a separate execution.

PushStreamContent and exceptions in the middle of streaming/serializing

We're using PushStreamContent to stream some large lumps with Content-Disposition headers set and the like. As a number of people have discovered, the drawback is what happens when something goes wrong in the streaming?
At the very least, we were trying to get the error logged on our side so someone could follow up.
Recently, I ran into a weird situation. Putting a try/catch around the streaming function worked well enough for errors encountered before you actually started streaming (i.e. errors in sql queries and the like), but if the error occurred later (like in the serialization), the catch block doesn't fire.
Would anyone have any idea why that is?
e.g.
HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
try
{
response.Content = new PushStreamContent((stream, content, context) =>
{
using (XmlWriter rWriter = PrepForXmlOutput(stream))
{
rpt.GenerateXmlReport(rWriter, reportParams, true);
}
}, "EventReport", extension);
}
catch (Exception e)
{
// The first step of GenerateXmlReport() is to run the sql;
// if the error happens there, this fires and will log the exception
// if the error happens later, during the result serialization, this does NOT fire
Log.Error(e);
}
return response;
Hate it when I see the answer just after I hit Post.
Try/catch around the outside only covers until I return the HttpResponseMessage. When/where I get the exception depends on how far the inner method gets before that return happens.
The try/catch needed to be on the inner call (the one where all the work happens) to cover the whole lifecycle.

sendReliableRealTimeMessage is not giving any callback

Here i'm using following code for sending message. I added the callback listener to know message status but its not printing any log message.
gamesClient.sendReliableRealTimeMessage(new RealTimeReliableMessageSentListener() {
#Override
public void onRealTimeMessageSent(int statusCode, int tokenId, String recipientParticipantId) {
// TODO Auto-generated method stub
switch (statusCode) {
case GamesClient.STATUS_OK:
Log.e("status", "STATUS_OK");
break;
case GamesClient.STATUS_REAL_TIME_MESSAGE_SEND_FAILED:
Log.e("status", "STATUS_REAL_TIME_MESSAGE_SEND_FAILED");
break;
case GamesClient.STATUS_REAL_TIME_ROOM_NOT_JOINED:
Log.e("status", "STATUS_REAL_TIME_ROOM_NOT_JOINED");
break;
}
}
}, msgBuf, roomId, p.getParticipantId());
Don't use anonymous listeners like that. The API uses weak references to listeners, so it often happens that these listeners will get garbage-collected before they are called. Please try again using a non-anonymous listener, that is, a listener that you hold a reference to. One easy way to do that is make the Activity the listener (i.e. add "implements RealTimeReliableMessageSentListener" to the Activity class).
Another option is to hold an explicit reference to the listener as a member variable in your Activity.

Switch Screens in BlackBerry

I have a BlackBerry App that has a Listener for the Send Button implemented in the CheckIn Screen. Data is sent through a web service. If the data is sent successfully, a confirmation message of "OK" is received. I am trying to switch screens in my BlackBerry App depending on the response received.
FieldChangeListener sendBtnListener = new FieldChangeListener() {
public void fieldChanged(Field field, int context)
{
try {
String alertMsg=sendTextCheckIn();
if(alertMsg.equals("OK"))
{
UiApplication.getUiApplication().invokeLater( new Runnable()
{
public void run ()
{
UiApplication.getUiApplication().pushScreen(new MyScreen());
}
} );
}
} catch (UnsupportedEncodingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
However, the above is throwing an App Error 104: IllegalStateException. Can anyone please guide on how to switch screens between a BlackBerry App.
EDIT: I can switch to any other screen but I CAN NOT switch to MyScreen. NOTE: MyScreen is the main (first) screen of the App. The above method sendTextCheckIn() calls another method that is placed inside MyScreen. Has this got anything to do with the error? Please advice.
The 'fieldChanged' event is already running on the UI event thread, so you shouldn't need to do the invokeLater call within it, just call pushScreen directly.
You mention that your problem with IllegalStateException only happens for MyScreen. That makes it sound like something specific with the implementation of MyScreen. Start narrowing down the problem - look at what happens in the constructor of MyScreen, and any events that might get called before the screen is visible. Some of that code is what is causing the problem.
Wrap everything that could possibly raise in exception in try/catch.
Don't do e.printStackTrace() - that won't give you much.
Instead do something like System.err.println ("KABOOM in method abc() - " + e); - seems like more effort, but trust me, that becomes INVALUABLE when debugging issues like this.
Catch Exception, unless you have a VERY good reason to catch a specific a subtype - otherwise you WILL end up with unexpected, and uncaught exceptions, which you will hunt for DAYS.

Resources