Hello resteasy users,
I am trying to use the new JAX-RS 2.0 @Suspended AsyncResponse mechanism to write
a service that expects many idling connections (awaiting an event via long-poll),
and therefore seems like a good candidate for asynchronous responses, so as not
to use a large number of waiting threads.
The resource code is very simple:
@GET
@Produces(MediaType.APPLICATION_JSON)
public void watchForChanges(
@Suspended AsyncResponse asyncResponse,
@QueryParam("since") long since)
{
controller.watchForChanges(since, asyncResponse::resume);
}
The intent is that watchForChanges places the (inferred) Consumer<ResponseObject> on
a queue,
and returns immediately. Later on a background thread comes by and completes the
request.
However, when testing with say 20 clients, it sure looks like the end result is still a
thread per request model:
"qtp1718322084-43" - Thread t@43
java.lang.Thread.State: WAITING
at sun.misc.Unsafe.park(Native Method)
- parking to wait for <3537ebd5> (a java.util.concurrent.CountDownLatch$Sync)
at java.util.concurrent.locks.LockSupport.park(LockSupport.java:175)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.parkAndCheckInterrupt(AbstractQueuedSynchronizer.java:836)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.doAcquireSharedInterruptibly(AbstractQueuedSynchronizer.java:997)
at
java.util.concurrent.locks.AbstractQueuedSynchronizer.acquireSharedInterruptibly(AbstractQueuedSynchronizer.java:1304)
at java.util.concurrent.CountDownLatch.await(CountDownLatch.java:231)
at
org.jboss.resteasy.core.SynchronousExecutionContext$SynchronousAsynchronousResponse.initialRequestThreadFinished(SynchronousExecutionContext.java:127)
at org.jboss.resteasy.core.SynchronousDispatcher.invoke(SynchronousDispatcher.java:411)
at
org.jboss.resteasy.core.SynchronousDispatcher.invokePropagateNotFound(SynchronousDispatcher.java:247)
at
org.jboss.resteasy.plugins.server.servlet.ServletContainerDispatcher.service(ServletContainerDispatcher.java:225)
at
org.jboss.resteasy.plugins.server.servlet.FilterDispatcher.doFilter(FilterDispatcher.java:62)
at
org.eclipse.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1676)
<snip Jetty handler / filter chain>
at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:319)
at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:253)
at
org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273)
at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93)
at
org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.executeProduceConsume(ExecuteProduceConsume.java:303)
at
org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:148)
at
org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:136)
at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:671)
at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:589)
at java.lang.Thread.run(Thread.java:745)
Locked ownable synchronizers:
- None
The concept of a "SynchronousAsynchronousResponse" and implementation of in
particular SynchronousDispatcher#invoke seem to be totally not what I want:
/**
* Callback by the initial calling thread. This callback will probably do
nothing in an asynchronous environment
* but will be used to simulate AsynchronousResponse in vanilla Servlet
containers that do not support
* asychronous HTTP.
*
*/
request.getAsyncContext().getAsyncResponse().initialRequestThreadFinished();
What am I doing wrong? How do I get truly asynchronous processing?
This is with RESTEasy 3.0.18 running on Jetty 9.3.11
Thanks for any advice,
Steven
Show replies by thread