long-running operations in Tomcat
Are there any suggested practices for implementing long-running operations in Tomcat?
e.g. is it better to just run the operation and not yield a response until the operation is complete? Or is it better to return immediately with some 开发者_如何学编程kind of ticket that can be used to poll for completion? (is there a way to notify a client that completion has occurred?)
You should return immediately with a status of 202 Accepted. Along with this, the HTTP spec agrees with Jonathan's answer:
The entity returned with this response SHOULD include an indication of the request's current status and either a pointer to a status monitor or some estimate of when the user can expect the request to be fulfilled.
You can set the status (in the servlet, for example) using:
response.setStatus(HttpServletResponse.SC_ACCEPTED);
Where response
is the HttpServletResponse
provided for the request.
Edit (re: comments):
Good browsers will treat any 2XX status as successful and will render the content provided in the response body to the user, so returning a 202 shouldn't affect web browser users and how they see pages. If the browser doesn't do this, it's probably violating Section 6.1.1 of the spec:
...applications MUST understand the class of any status code, as indicated by the first digit, and treat any unrecognized response as being equivalent to the x00 status code of that class...
Since a Tomcat server is just a specialized HTTP server, you should try to stick to the specification as much as possible (i.e. returning as appropriate a status as possible). Even if you intend your site to be accessed by a browser, there's nothing stopping other clients (curl, etc.) from requesting a page. If you provide specific statuses, clients can act more appropriately to responses.
For the sake of your server not falling down, and for the sake of not frustrating your user, it is definitely preferable to immediately return with, as you suggest, a "ticket" of some kind, and then to poll periodically for completion of that ticket.
If it's a very long-running operation, you might consider sending an email (such as Vimeo does, for example, when they've re-encoded your video).
Depend on how long you operation will be executed. I'm use both methods depend on situation. I'm have a servlet for usual browser, that wait several seconds and all ok, but another servlet for accessing from PDA fail on long timeouts and i'm return response imm. after putting request into queue. In summary i'm think second way better in general.
If you are using a Servlet 3.0 conformant server (like Tomcat) then you can get an AsyncContext instance with ServletRequest.startAsync() or (in some servers) ServletRequest.getAsyncContext() (use recommended way to avoid automagically created threads).
After getting AsyncContext store it somewhere in your app and return inmediatly from the server request thread call immediately so all non-necesary resources are released. Then you can decide how to manage thousands of parallel connections in a more lightweight way avoiding the bottlenecks of using classic per-connection thread.
- https://docs.oracle.com/javaee/6/api/javax/servlet/ServletRequest.html#startAsync()
- https://docs.oracle.com/javaee/6/api/javax/servlet/ServletRequest.html#getAsyncContext()
You must check also your concrete server's version documentation about parallelism and AsyncContext usage and do lots of trial and error for tuning because some servers recomends specific ways to approach the problem and it can change even between versions. Be careful with testing when server is updated and use LTS always.
There are some caveats while using AsyncContext on a thread-light environment like output stream can block the calling thread... which would normally break all the magic. There are some tricks like the ones described at Servlet-3 Async Context, how to do asynchronous writes? but it can depend on server implementation... the always-work solution is use a thread pool worker for writing outputs if no other works-for-you... with maybe a few dozen of threads you can serve thousands of connections.
I see this question by chance while trying to remember the methods names and classes so this answer is a bit late... and currently there are other more simple and direct Java solutions like Jetty, Netty, ... but if somebody needs to use a corporative "classic" server like Tomcat this may help as long as AsyncContext exists since Servlet 3.0 (which is pretty old and should be supported).
精彩评论