Stream of big answers with knit, asynchronously

I want to allow clients (including very slow clients) to download large files from the JAX-RS web service (jersey), and I am stuck. It seems that async fatures in JAX-RS does not support this.

  • AsyncResponsesolves the problem if you need to wait until the resource becomes available on the server side, but then you are allowed to call AsyncResponse.resume(Object)only once. After that, the response is processed normally. Slow or malicious clients block the workflow until all bytes are transferred. There is no asynchronous I / O.
  • ChunkedOutputin jersey stores pieces in an unlimited queue in memory and does not offer any open interface for checking the size of this queue. It is designed for a slow flow of small pieces. Slow enough customers will eventually call OutOfMemoryError.
  • StreamingOutputnot asynchronous at all. It is assumed that the method is StreamingOutput.write(OutputStream)blocked until all bytes have been written.
  • The Servlet 3.x API supports what I need, but I cannot find a way to get to the servlet level ( HttpServletRequest.startAsync) from the JAX-RS request handler without breaking the internal elements of the jersey. β†’IllegalStateException

I do not see the obvious solution?

+4
source share
2 answers

, :

  • @Suspended AsyncResponse jax-rs. , .
  • Inject @Context HttpServletRequest API .
  • HttpServletRequest.getAsyncContext() HttpServletRequest.startAsync(), , IllegalStateException ( ).
  • AsyncContext, . .
  • , AsyncContext.complete(), AsyncResponse.cancel(). , .

10- 100 . ~ 40 , . 3 / , .

@GET
public void doAsync(@Suspended final AsyncResponse asyncResponse,
                    @Context HttpServletRequest servletRequest)
        throws IOException {
    assert servletRequest.isAsyncStarted();
    final AsyncContext asyncContext = servletRequest.getAsyncContext();
    final ServletOutputStream s = asyncContext.getResponse().getOutputStream();

    s.setWriteListener(new WriteListener() {

        volatile boolean done = false;

        public void onWritePossible() throws IOException {
            while (s.isReady()) {
                if(done) {
                    asyncContext.complete();
                    asyncResponse.isCancelled();
                    break;
                } else {
                    s.write(...);
                    done = true;
                }
            }
        }
    });
}
+2

, . . StreamingOutput, , , , TimeOutException. , Grizzly. , StreamingOutput . - :

Collection<NetworkListener> listeners = server.getListeners(); 
for(NetworkListener listener : listeners) {
    final TCPNIOTransport transport = listener.getTransport();
    transport.setKeepAlive(true);
    transport.setWriteTimeout(0, TimeUnit.MINUTES);
}
0

Source: https://habr.com/ru/post/1661588/


All Articles