AsyncResponse ConnectionCallback 不会在泽西岛触发

Posted

技术标签:

【中文标题】AsyncResponse ConnectionCallback 不会在泽西岛触发【英文标题】:AsyncResponse ConnectionCallback does not fire in Jersey 【发布时间】:2015-01-03 19:51:45 【问题描述】:

对于异步编程,Jersey (JAX-RS) 提供了一个ConnectionCallback 回调,该回调将在连接断开时执行。来自Jersey docs:

由于一些异步请求可能需要很长时间来处理客户端可能 决定在响应之前终止其与服务器的连接 已恢复或在完全写入客户端之前。到 处理这些用例可以使用 ConnectionCallback。这 仅当连接过早时才会执行回调 在将响应写入背面时终止或丢失 客户。请注意,响应时不会调用此回调 写入成功,客户端连接按预期关闭。

听起来不错,但我永远无法点燃它。

这里有一些代码:

@GET
@Produces(MediaType.TEXT_PLAIN)
@ManagedAsync
@Path("/poll")
public void poll(@Suspended final AsyncResponse asyncResponse) 
    asyncResponse.register(new CompletionCallback() 
        @Override
        public void onComplete(Throwable throwable) 
            logger.info("onComplete called.");
        
    );

    asyncResponse.register(new ConnectionCallback() 
        @Override
        public void onDisconnect(AsyncResponse disconnected) 
            logger.info("onDisconnect called.");
        
    );

    asyncResponse.setTimeout(POLL_TIMEOUT_SECONDS, TimeUnit.SECONDS);
    asyncResponse.setTimeoutHandler(new TimeoutHandler() 
        @Override
        public void handleTimeout(AsyncResponse asyncResponse) 
            logger.info("handleTimeout called.");
            asyncResponse.resume(Response.status(Response.Status.OK).entity("TIMEOUT").build());
        
    );

显示的另外两个回调,CompletionCallback 和 TimeoutHandler,触发得很好,没有失败。如果达到指定的超时持续时间,TimeoutHandler 将触发。如果 AsyncResponse 实例被恢复,则 CompletionCallback 触发。

但是,使用 ConnectionCallback,我可以关闭、终止或以其他方式停止连接到上面显示的 Web 服务的客户端,并且 ConnectionCallback 永远不会被触发。

我错过了什么吗? ConnectionCallback 是否在泽西岛实现? (在 JAX-RS 规范中它是可选的,但 Jersey 文档谈论它好像它已经实现了。)

我们将不胜感激。

【问题讨论】:

【参考方案1】:

ConnectionCallback 确实在 Jersey 中实现。并且还调用了“onDisconnect”回调。您可以在 Jersey 中查看以下代码:

https://github.com/jersey/jersey/blob/a6ff4d50da13d45ad90fd7375a15a31afa02e489/core-server/src/main/java/org/glassfish/jersey/server/ServerRuntime.java#L723

https://github.com/jersey/jersey/blob/b7907e279010e7035a7a3e529993d22f77a21e08/core-server/src/main/java/org/glassfish/jersey/server/ChunkedOutput.java#L246-L252

在写响应时抛出 IOException。因此,为了回答您的问题,没有轮询或类似机制不断检查客户端是否已连接,而是仅在写入响应时通常发生 IOException 时才调用 onDisconnect 方法。

更新 1:

另外我想引用你自己的问题:

"只有在连接过早的情况下才会执行此回调 在将响应写入背面时终止或丢失 客户”

因此,除非您尝试写入该流,否则您的回调将永远不会被触发。需要明确的是,当没有写入响应或响应为 202 时调用它并不意味着调用它,而是意味着当连接过早终止时调用它在写入响应时

恐怕没有解决此问题的方法,除非您编写一些带有某种轮询的低级网络编程。但我不建议你这样做。

我建议您重新考虑处理此故障的方式。

【讨论】:

您好,感谢您的回答。我已经确定它是在泽西岛实现的,尽管在我的调试中我永远无法通过各种终止客户端连接的方式触发onDisconnect,尽管这可能是特定于环境的。另外,为了赏金,我需要知道如何处理 onDisconnect 似乎只会在尝试编写响应之后才会发生的事实,即在您认为请求完成以及为什么在没有实体时不引用它之后写(try catch 只是围绕写实体,而不是 204) 您好,感谢您的更新,无论在编写 202 响应时是否应该调用它,因为即使没有正文,它仍在向客户端发送响应。 javadoc 声明“如果容器检测到与异步响应关联的远程客户端连接已断开,则会调用此回调通知方法。”。因此,即使它在完成请求后确实调用了 onDisconnect(我猜这很好),如果正在写入非正文响应,它也不会。 我认为你说得对,不过我需要另一种方式来考虑它......我真的在尝试解决一个外部强加的约束,它只会导致糟糕的 API 设计! :S 如果您想处理响应完成,您已经拥有CompletionCallback,正如您在问题中提到的那样。我猜它会在 202 年被解雇。

以上是关于AsyncResponse ConnectionCallback 不会在泽西岛触发的主要内容,如果未能解决你的问题,请参考以下文章

Mybatis

jdbc

事务管理

简单的Dao层的模板写法

mysql和oracle的驱动方式

统计删除的记录,返回 0