When does servlet release its thread - java

Assuming no keep alives, when a servlet container is acting as a stand alone server, I assume that the servlet's thread is not released until the entire response is sent to the client (say a web browser). Is this a correct assumption?
But what happens if the servlet is behind a reverse proxy like Nginx? Is the thread released once the response is delivered to Nginx, or is it held until the response is sent to its final client (say a browser)?
Update: Let me try make this a bit more clear.
It takes mere milliseconds (say 2ms) for a response to be sent from servlet to proxy like nginx. But it can then take an additional 80ms (or so) for the final response to be sent from nginx to the browser. Does the servlet release the thread/stream once the response is sent to nginx, or does the servlet hold onto them until the response is sent to the browser (that is the entire 80ms)

Question: I assume that the servlet's thread is not released until the entire response is sent to the client (say a web browser). Is this a correct assumption?
Ans: No it is wrong. Servlet container will just write the content to the socket and return. It is not guaranteed that return from write() method will ensure that the response has reached the client.
Question: Is the thread released once the response is delivered to Nginx, or is it held until the response is sent to its final client (say a browser)?
Ans: When Nginx is behind , then the client for Servlet container is Nginx. It is not aware of actual remote client. So, the thread will be released once the response is written to Nginx.

The server container not being able to send a response to the client will trigger an exception that will be handled by the container. You can enclose the writing to the outputstream or writer by a try catch finally (with close()) but you don't need to, the container will manage, including the return of the thread to the pool.
Regards
S

A servlet does not see the network. According to the specifications It is handled 2 objects: a Request and a Response to be filled in (in the case of HTTP, this means a HTTPRequest and a HTTPResponse). It shall process the request data within the request object, and write to the buffer in the response object. Once that content is commited by the servlet, the container may do some postprocessing (using filters) and will transmit it back to the client.
The servlet thread returns naturally to the pool once the call to the request handling method finishes (that may happen after the payload is sent back to the client, if the method has to do further work.
Note that because the servlet doesn't see the network and is only concerned about a single request, the state of the http connection (keep-alive or close) is independent of the servlet lifetime; several servlets may handle the different requests pipelined in a single connection. See this question for a related issue.

Related

Does Servlet return response after doGet method has finished?

Obviously, the doGet method has a return type of void, so, it doesn't return anything. In this sense, I'm using the word "return" to mean send the response back to the client that requested it.
I'm trying to implement a long-polling Servlet. It would be beneficial for it not to send a response until I have something that I would like to send back. So, in the doGet method I add the connected user's ID and AsyncContext to a map:
private ConcurrentMap<String, AsyncContext> contexts = new ConcurrentHashMap<>();
//...in the doGet method when I need to add the context...
contexts.put(userId, context);
Then, when I have something to send back, I can retrieve the appropriate context and write to it's responses output stream:
AsyncContext context = contexts.get(userId);
PrintWriter writer = context.getResponse().getWriter();
writer.write("something to send to the client");
But, the client never seems to receive the response. Looking at the Network tab in the developer console of the browser, I can see the GET request is sent and then returns (with a status of 200). This occurs before I actually send something back. Which is leading me to believe that after the doGet method is finished the response is returned. And perhaps because of this, after this point, nothing can be sent to the client because the connection is not opened.
Does the doGet method send the response to the client once the method is finished executing? If this is the case, how can I keep the connection open for a long-polling effect?
To answer my own questions: Does the doGet method send the response to the client once the method is finished executing?
Yes, when the doGet (or any HttpServlet method, ex: doGet, doPost, etc.) method finishes executing it sends the response back to the client.
If this is the case, how can I keep the connection open for a long-polling effect?
Using asynchronous Servlets (which I was using, however, I found my particular problem must be elsewhere, yet these answers are still relevant to the questions asked). On the ServletRequest object call the startAsync method, like so:
AsyncContext context = request.startAsync(request, response);
"This will notify the Web Container that at the end of the request call it should free the handling thread and leave the connection open so that other thread writes the response and end the connection."Reference Link.
Also, I will add the solution to my particular problem (the client wasn't receiving the response) was because in my Servlet, I wasn't calling the complete method on the AsyncContext object:
asyncContext.complete();
Yes, the response stream is flushed and closed when doGet() finishes executing.
Keeping UI threads occupied for extended periods of time violates Java Enterprise best practice.
Recommend you rather return immediately if nothing to respond, and implement a timer on the client (browser) side to poll the server for results every so often.

Netty client with synchronous request response

i am trying to create a http client based on netty. I have written the code based on the HttpSnoopClient example given in Netty site. But the problem is HttpResponse are handled by HttpSnoopClientHandler & HttpRequests are sent in HttpSnoopClient & i want to sync it. as in if i send a request i want to make sure that i will send the next request once i know the response to the previous. But since both are handled in different class, It is becoming difficult to do the same.
One thing i did was to create a setResponse() method in HttpTarget & HttpSnoopClientHandler will be setting the HttpResponse when it receives the Response from the sever. But i don't think it is a good approach since i won't be able to know the reposne was for which request.
So basically i want to do it synchronously i.e. send a request(channel.writeandFlush(req)) in HttpSnoopClient then wait till the response is received by the HttpSnoopCLientHandler & once it recieves a HTTP 1.1 200 OK then send the next request.
Can anyone tell me a good approach for doing it. Thanks in advance!
I had a similar use case where I had to block concurrent requests till one completes for a resource. I implemented a ConcurrentHashMap<RequestKey, ArrayList<ChannelHandlerContext>>> which will hold all the concurrent requests ChannelHandlerContext (ctx) and on completion of the first request raise an event which would trigger all other ctx to consume the cached response. In all this I had to make sure the AUTO_READ was set to false for fine grain control over the reads on each channel.
channelRead ->
if(map.contains(reqKey)){
map.add(reqKey, list.add(ctx))
//do nothing with AUTO_READ = false and do not initiate any ctx.* methods
}else{
//firstRequest
map.add(reqKey, new ArrayList<CTX>(){{ add(ctx);}})
//continue with request execution
//cache response and raise event on completion
}
userEventTriggered ->
onCompletionEvent {
ctxList = map.get(reqKey).clone();
map.remove(reqKey);
for(blockedCtx : ctxList){
//respond back with cached response to each blockedCtx
}
}
#norman-maurer would you give your take on this !!!
As you're creating a new HttpSnoopClientHandler for each connection, I would consider turning HttpSnoopClientHandler into a ChannelDuplexHandler. In the write method you can store a reference to the outgoing http request. When the response is received you can call your setResponse method with (channel, request, response). This should provide enough context so you can process the response correctly.
If your client is pure request/response, does not issue unrelated requests separately, and you want your application thread to process responses sequentially, then you could use a SynchronousQueue to coordinate responses with allowing the main thread to continue. Alternatively your callback can process the responses internally.
You can also extends this technique to use HTTP pipelining. HTTP pipelining guarantees that responses are returned in the order that requests are issued. In HttpSnoopClientHandler you maintain a queue of requests. As each response is returned you match it to the request at the front of the queue.

Check with a servlet API if the client is continue listen on the request?

We have some long running Servlet's request? We want stop this requests on the server if the client give up. Is it possible to detect via Servlet API whether the client has close the HTTP connection in the mean time ?
Write a byte (space character?) to the response and flush. If it throws IOException, then you know enough.
By the way, a real background job (e.g. with #Asynchronous EJB), in combination with a kind of email notification with a specific link on finish, is likely a more user friendly approach.

Asynchronous web service SOAP

I have an interface that I've exposed as a regular SOAP web service. One method of the interface consists for the client to send a file to the server, then the server processes the file and returns a result file. Processing the file may take some time, so I think using asynchronous invocation of this method is a better idea. I thought about the following flow:
The client invokes the asynchronous method and sends the file using an attachment (MTOM).
When the file is received by the server, a response is sent back to the client indicating that the file has been received and that it will be processed shortly.
Once the file is processes, a response is sent back to the client indicating it has been processed and a result file is returned in the response also as an attachment.
Is it possible using SOAP with CXF?
Thanks
You can use Callback approach of Asynchronous InvocationModel.
Callback approach - in this case, to invoke the remote operation, you
call another special method that takes a reference to a callback
object (of javax.xml.ws.AsyncHandler type) as one of its parameters.
Whenever the response message arrives at the client, the CXF runtime
calls back on the AsyncHandler object to give it the contents of the
response message
More information can be had from the following:
Apache CXF
If you use some tool like WSDL2Java for client generation, you can even choose to generate an asynchronous client.
It will generate for you a callback handler with empty methods for each of the service operations and exceptions of the service. You then can just implement those methods to set the actions to do when the response is received.
Remember that when an asynchronous call is done a new thread is started.
Yes, Once you receive the file, you may return the request id to client and start processing on server side and do maintain various states of processing. Client can come back in different interval, and will receive the processing status or the output if it is completed.

Servlet 3.0: Can't send an asynchronous response?

I'm having trouble establishing AsyncContexts for users and using them to push notifications to them. On page load I have some jQuery code to send the request:
$.post("TestServlet",{
action: "registerAsynchronousContext"
},function(data, textStatus, jqXHR){
alert("Server received async request"); //Placed here for debugging
}, "json");
And in "TestServlet" I have this code in the doPost method:
HttpSession userSession = request.getSession();
String userIDString = userSession.getAttribute("id").toString();
String paramAction = request.getParameter("action");
if(paramAction.equals("registerAsynchronousContext"))
{
AsyncContext userAsyncContext = request.startAsync();
HashMap<String, AsyncContext> userAsynchronousContextHashMap = (HashMap<String, AsyncContext>)getServletContext().getAttribute("userAsynchronousContextHashMap");
userAsynchronousContextHashMap.put(userIDString, userAsyncContext);
getServletContext().setAttribute("userAsynchronousContextHashMap", userAsynchronousContextHashMap);
System.out.println("Put asynchronous request in global map");
}
//userAsynchronousContextHashMap is created by a ContextListener on the start of the web-app
However, according to Opera Dragonfly (a debugging tool like Firebug), it appears that the server sends an HTTP 500 response about 30000ms after the request is sent.
Any responses created with userAsyncContext.getResponse().getWriter().print(SOME_JSON) and sent before the HTTP 500 response is not received by the browser, and I don't know why. Using the regular response object to send a response (response.print(SOME_JSON)) is received by the browser ONLY if all the code in the "if" statement dealing with AsyncContext is not present.
Can someone help me out? I have a feeling this is due to my misunderstanding of how the asynchronous API works. I thought that I would be able to store these AsyncContexts in a global map, then retrieve them and use their response objects to push things to the clients. However, it doesn't seem as if the AsyncContexts can write back to the clients.
Any help would be appreaciated.
I solved the issue. It seems as though there were several problems wrong with my approach:
In Glassfish, AsyncContext objects all have a default timeout period of 30,000 milliseconds (.5 minutes). Once this period expires, the entire response is committed back to the client, meaning you won't be able to use it again.
If you're implementing long-polling this might not be much of an issue (since you'll end up sending another request after the response anyway), but if you wish to implement streaming (sending data to back to the client without committing the response) you'll want to either increase the timeout, or get rid of it all together.
This can be accomplished with an AsyncContext's .setTimeout() method. Do note that while the spec states: "A timeout value of zero or less indicates no timeout.", Glassfish (at this time) seems to interpret 0 as being "immediate response required", and any negative number as "no timeout".
If you're implementing streaming , you must use the printwriter's .flush() method to push the data to the client after you're done using its .print() .println() or .write() methods to write the data.
On the client side, if you've streamed the data, it will trigger a readyState of 3 ("interactive", which means that the browser is in the process of receiving a response). If you are using jQuery, there is no easy way to handle readyStates of 3, so you're going to have to revert to regular Javascript in order to both send the request and handle the response if you're implementing streaming.
I have noticed that in Glassfish if you use AsyncContext and use .setTimeOut() to a negative number the connection is broken anyway, to fix this I had to go to my Glassfish admin web configurator : asadmin set
configs.config.server-config.network-config.protocols.protocol.http-listener-1.http. And set timeout to -1. All this to avoid glassfish finish the connections after 30 sec.

Categories