We have a server-side stream structure, the thing is the server side is a multi-thread environment where the streamObserver will be passed between methods and even threads, I have put the code where the .onNext() is called in a synchronized block but still it does not do the work.
When in unit tests, it passes the test only half of the time and when the test fails sometimes I got call is closed error, sometimes I got Stream is already completed, no further calls are allowed. My understanding is that those errors indicate the client side has closed the connection when the server is still trying to send response but I'm just confused when and how did the client closed the connection?
server-side code:
synchronized (responseObserver) {
try {
responseObserver.onNext(response);
} catch (Exception e) {
System.out.println("=== exception: ");
e.printStackTrace();
}
eventsAsync.addAll(currentEvents);
}
exception:
java.lang.IllegalStateException: call is closed
at com.google.common.base.Preconditions.checkState(Preconditions.java:508)
at io.grpc.internal.ServerCallImpl.sendMessageInternal(Unknown Source)
at io.grpc.internal.ServerCallImpl.sendMessage(Unknown Source)
at io.grpc.stub.ServerCalls$ServerCallStreamObserverImpl.onNext(Unknown Source)
Related
I have web app on Azure with 2 slots.
Whenever the slot swap happens, all SignalR clients are disconnected and not even notified about the connection loss.
SignalR events such a Close, Error, Reconnected are never fired on the client.
How to prevent this or at least know when disconnect happens? (of course I need to avoid polling)
How to prevent this or at least know when disconnect happens?
We could enable SignalR tracing to view diagnositc infomration about events in your SignalR application. How to enable and configure tracing for SignalR servers and clients, we could refer to this document.
Detecting the reason for a disconnection
SignalR 2.1 adds an overload to the server OnDisconnect event that indicates if the client deliberately disconnected rather than timing out. The StopCalled parameter is true if the client explicitly closed the connection. In JavaScript, if a server error led the client to disconnect, the error information will be passed to the client as $.connection.hub.lastError.
C# server code: stopCalled parameter
public override System.Threading.Tasks.Task OnDisconnected(bool stopCalled)
{
if (stopCalled)
{
Console.WriteLine(String.Format("Client {0} explicitly closed the connection.", Context.ConnectionId));
}
else
{
Console.WriteLine(String.Format("Client {0} timed out .", Context.ConnectionId));
}
return base.OnDisconnected(stopCalled);
}
JavaScript client code: accessing lastError in the disconnect event.
$.connection.hub.disconnected(function () {
if ($.connection.hub.lastError)
{ alert("Disconnected. Reason: " + $.connection.hub.lastError.message); }
});
More details we could refer to Detecting the reason for a disconnection.
How to prevent this?
We could continuously reconnect it.
In some applications you might want to automatically re-establish a connection after it has been lost and the attempt to reconnect has timed out. To do that, you can call the Start method from your Closed event handler (disconnected event handler on JavaScript clients). You might want to wait a period of time before calling Start in order to avoid doing this too frequently when the server or the physical connection are unavailable. The following code sample is for a JavaScript client using the generated proxy.
$.connection.hub.disconnected(function() {
setTimeout(function() {
$.connection.hub.start();
}, 5000); // Restart connection after 5 seconds.
});
More details we could refer to How to continuously reconnect
I'm struggling to find any good examples on how to implement error handling with Spring WebFlux.
The use case I want to handle is notifying HTTP clients that a stream has terminated unexpectedly. What I have found it that with the out of the box behaviour, when a stream is terminated, for example by raising a RuntimeException after x items have been processed, is handled too gracefully! The client is flushed all items up until the exception is raised, and then the connection is closed. As far as the client is concerned the request was successful. The following code shows how this has been setup:
public Mono<ServerResponse> getItems(ServerRequest request) {
Counter counter = new Counter(0);
return ServerResponse
.ok()
.contentType(MediaType.APPLICATION_STREAM_JSON)
.body(operations.find(query, Document.class, "myCollection")
.map(it -> {
counter.increment();
if(counter.getCount() > 500) {
throw new RuntimeException("an error has occurred");
}
return it;
}), Document.class);
}
What is the recommended way to handle the error and notify the HTTP client that the stream terminated unexpectedly?
It really depends on how you'd like to communicate that failure to the client. Should the client display some specific error message? Should the client reconnect automatically?
If this is a "business error" that doesn't prevent you from writing to the stream, you could communicate that failure using a specific event type (look at the Server Sent Events spec).
Spring WebFlux supports ServerSentEvent<T>, which allows you to control various fields such as event, id, comment and data (the actual data). Using an Flux::onErrorMap operator, you could write a specific ServerSentEvent that has an "error" event type (look at the ServerSentEvent.builder() for more).
But this is not transparent to the client, as you'd have to subscribe to specific events and change your JavaScript code otherwise you may display error messages as regular messages.
I was trying to understand Asynchronous Controller implementation from one of links:
http://shengwangi.blogspot.in/2015/09/asynchronous-spring-mvc-hello-world.html
I was puzzled on point that Controller thread received request and exists. Then service method received the request for further processing.
#RequestMapping("/helloAsync")
public Callable<String> sayHelloAsync() {
logger.info("Entering controller");
Callable<String> asyncTask = new Callable<String>() {
#Override
public String call() throws Exception {
return helloService.doSlowWork();
}
};
logger.info("Leaving controller");
return asyncTask;
}
Since, Controller exists it and pass the control to appropriate handler mapping/ jsp. What will be seen on the browser for the user ?
Browser waits for the response to process it.
Asynchronous process takes place only at the server end and it has nothing to do with the browser. Browser sends the request and waits for the server to write the response back.
Since you returned Callable doesnt mean that controller exists the flow. Spring`s response handlers will wait for async task to get executed to write the response back.
Please go through AsyncHandlerMethodReturnValueHandler which handles Asynchronous response returned from the controller.
if you return callable then it will be handled by CallableHandlerMethodReturnvaluehandler :
public void handleReturnValue(Object returnValue, MethodParameter returnType,
ModelAndViewContainer mavContainer, NativeWebRequest webRequest) throws Exception {
if (returnValue == null) {
mavContainer.setRequestHandled(true);
return;
}
Callable<?> callable = (Callable<?>) returnValue;
WebAsyncUtils.getAsyncManager(webRequest).startCallableProcessing(callable, mavContainer);
}
I had cleared my doubt from this link:
https://dzone.com/articles/jax-rs-20-asynchronous-server-and-client
However, they used different way to accomplish the asynchronous processing but the core concept should be the same for every approach.
Some important part of the article:
The idea behind asynchronous processing model is to separate
connection accepting and request processing operations. Technically
speaking it means to allocate two different threads, one to accept the
client connection and the other to handle heavy and time consuming
operations. In this model, the container dispatched a thread to accept
client connection (acceptor), hand over the request to processing
(worker) thread and releases the acceptor one. The result is sent back
to the client by the worker thread. In this mechanism client’s
connection remains open. May not impact on performance so much, such
processing model impacts on server’s THROUGHPUT and SCALABILITY a lot.
I use network connection from a struts application to connect to a network resource and download a file directly to the browser without storing it on the struts running server (need to avoid polluting the struts server with transported files). I use the result type stream to actually download the inputstream from the network resource directly to the user's browser and the inputstream is automatically closed but the network connection that carries the stream is never returned (there is a connection pool as I use httpclient for the network connection).
is there any way anyone can see to actually get code called after the result (of type stream) is finished (file has downloaded to the browser)?
In fact this is indeed solved by an interceptor:
I have written the following in an interceptor of the Action:
public String intercept(ActionInvocation invocation) throws Exception {
try {
return invocation.invoke();
} finally {
DownloadAction da = (DownloadAction) invocation.getAction();
if (null != da && null != da.getResponse()) {
logger.debug("###### connection releasing");
da.getResponse().releaseConnection();
}else{
logger.error("###### connection cannot be released");
}
}
}
Contrary to my previous belief this actually runs only after all results are executed (stream downloaded). It turns out I had been releasing the connection way to soon so I was getting a confusing error in the logs that I thought it was because the interceptor was running too soon. I was wrong.
I hope this may one day help someone else out there.
I need some advice on a good exception handling strategy in my webservice.
My web service methods are doing the standard CRUD operations against an Oracle database. Therefore, I have some methods that select data and return a dataset and others that do either an insert/update/ or delete and don't return anything.
Initially, I had all my code in each webservice method in a try-catch-finally catching an Oracle exception. I read some articles on the web that says this is not good and I should only surround something in try-catch if there is a potential for an exception. Now I am thinking that maybe it would be best if I put only my Insert/Update/Delete methods in try-catch-finally blocks.
So my questions are:
Should I put all my methods in try-catch-finally? They all interact with Oracle and could potentially cause an exception. Or should I only do this for the Insert/Update and Delete methods?
I don't really have any requirements on what they want to happen when an exception does occur. I am just going on common sense. I know that they definitely don't want the app to end. I am planning on logging the exception in some manner and re-throwing it to the client. I am doing this when there is an Oracle Exception.
Basically you need to do try-catch on every WebMethod. Since the event won't bubble up, I think there is no other better way.
However, you can use the trick in this post to make your life easier.
The way he does is creating a utility method like this and invoke that method by passing it a delegate to your web method logic.
private T Execute<T>(Func<T> body)
{
//wrap everything in common try/catch
try
{
return body();
}
catch (SoapException)
{
//rethrow any pre-generated SOAP faults
throw;
}
catch (ValidationException ex)
{
//validation error caused by client
ClientError innerError = new ClientError();
//TODO: populate client error as needed
//throw SOAP fault
throw this.GenerateSoapException(
"An error occurred while validating the client request.",
SoapException.ClientFaultCode,
innerError);
}
catch (Exception ex)
{
//everything else is treated as an error caused by server
ServerError innerError = new ServerError();
//TODO: populate server error as needed
//TODO: log error
//throw SOAP fault
throw this.GenerateSoapException(
"An unexpected error occurred on the server.",
SoapException.ServerFaultCode,
innerError);
}
}
I assume you are using ASP.NET WebMethods. My advice is that you always catch exceptions on the service layer, write a log and throw a SoapException. Basically you can try-catch on each service method (WebMethod). If you fail to do so, you would be exposing exception details to the client calling the service and that could be a potential security issue.