在servlet重新部署之前清除异步请求的正确方法是什么(Jersey,Tomcat)?

时间:2016-06-21 02:18:39

标签: java tomcat asynchronous jersey jax-rs

我有一个异步 JAX-RS API,用于在 Jersey容器Servlet 2.22 中放置并在 Tomcat 7 上托管的长轮询客户端。

它看起来类似于下面显示的代码段。它在生产中运作良好。

平均有150个长轮询请求同时执行。它导致几乎相同数量的实时Tomcat HTTP连接(根据JMX指标)。对于这种低流量情况,使用普通的 HTTP-BIO 连接器没有问题。如果仅使用托管线程,则无法检测到运行时连接泄漏:)

@Path("/v1/events")
public class LiveEventsResource {

    private static final long longPollTimeoutMs = 30000;

    private ExternalResource externalResource = ExternalResourceProvider.provide();

    private AsyncResponse asyncResponse;

    @POST
    @Path("/liveEvents")
    @ManagedAsync
    public void getResult(@Suspended final AsyncResponse asyncResponse, RequestPayload payload) {
        this.asyncResponse = asyncResponse;
        asyncResponse.setTimeout(longPollTimeoutMs, TimeUnit.MILLISECONDS);
        asyncResponse.setTimeoutHandler(new TimeoutHandler() {
            @Override
            public void handleTimeout(AsyncResponse asyncResponseArg) {
                try {
                    asyncResponseArg.cancel();
                } finally {
                    cleanupResources();
                }
            }
        });
        startListeningForExternalEventsAndReturn(payload);
    }

    private void startListeningForExternalEventsAndReturn(RequestPayload payload) {
        externalResource.register(new Listener() {
            @Override
            public void onEvent(Event event) {
                respond(event);
            }
        });
    }

    private void respond(Event event) {
        try {
            asyncResponse.resume(event);
        } catch (RuntimeException exception) {
            asyncResponse.resume(exception);
        } finally {
            cleanupResources();
        }
    }

    protected void cleanupResources() {
        externalResource.cleanup();
    }

}

我面临的问题是,在成功的 Tomcat 重新部署过程之后,实时连接的数量显然将增加到大约300,然后增加到450,并且在进行一些进一步的重新部署后,它将达到{{1为容器配置的限制。

API的客户端通过等待客户端超时(当然大于servlet端设置的超时)来处理重新部署,并再次开始轮询API。但他们保证只能同时发送一个请求。

连接计数监控图的形状给出了提示。取消部署后连接计数保持不变(即使maxConnection也没有将连接释放回池中),并且当客户端再次开始长轮询时开始增加(分配新连接)。 事实上,在JVM终止之前,在上一个上下文中启动的正在进行的(暂停的)异步请求永远不会被释放!

经过一些挖掘后,通过分析未经释放的少量重新部署之后进行的堆转储不难发现,暂停的TimeOutHandlerAsyncResponse)实例仍保留在以前的Web应用程序上下文的内存中(可轻松过滤)按AsyncResponder个实例分组的JQL查询。同样数量的过时Classloader个实例在以前的上下文中存在于内存中也是非常可疑的。

我开始环顾 Jersey容器的取消部署相关的源代码,希望在org.apache.coyote.Request时执行一些清理操作,为异步请求实现一些优雅的关闭过程。在@PreDestroy的{​​{1}}或close()方法中。

我乐观地猜测,在取消部署之前运行每个预定的dispose()就可以解决问题。但是将默认的Provider提供程序(TimeOutHandler)替换为自定义实现并收集@BackgroundScheduler的所有排队DefaultBackgroundSchedulerProvider并最终调用TimeoutHandler或{{1他们没有帮助。此阶段对于此清理可能为时已晚,因为请求范围已经关闭。

关于我的异步设置缺失的内容或者 Jersey 如何配置以释放 Servlet容器在重新部署时仍然挂起的连接的任何想法?< / p>

0 个答案:

没有答案