用于长时间运行过程的 Spring SSE

Posted

技术标签:

【中文标题】用于长时间运行过程的 Spring SSE【英文标题】:Spring SSE for Long Running Process 【发布时间】:2018-09-05 10:44:03 【问题描述】:

我有一个使用 Spring 开发的 REST API,Angular 5 前端使用它。我的服务大约需要 5 分钟才能完成,并且我的负载均衡器断开了来自浏览器的连接。

我们无法实现 WebSocket,因为 ws 协议被代理阻止。我们想在服务器端实现 Spring SSE,在 Angular 作为客户端实现 EventSource。

我们有以下客户端和服务器代码。

当异步处理完成并且服务器尝试发送响应时,我们遇到了以下错误。我无法理解这是 Tomcat 捕捉连接还是浏览器?

17:32:40.101 [GithubLookup-1] INFO  o.a.coyote.http11.Http11Processor - An error occurred in processing while on a non-container thread. The connection will be closed immediately
java.io.IOException: An established connection was aborted by the software in your host machine
    at sun.nio.ch.SocketDispatcher.write0(Native Method)
    at sun.nio.ch.SocketDispatcher.write(SocketDispatcher.java:51)
    at sun.nio.ch.IOUtil.writeFromNativeBuffer(IOUtil.java:93)

代码

public SseEmitter doSomething() 
      final SseEmitter emitter = new SseEmitter(600000L);
      CompletableFuture<Response> res = ... some Service call which takes 5 min, but annotated with @Async
      completableFuture.whenComplete((res, ex) -> 
        emitter.send(res);
        emitter.complete();
      
      emitter.send("Running"); // Some fake status to let client know it is accepted and running
      return emitter;
    

在客户端我们使用事件源

  let eventSource = new EventSource(url, 
      xhrHeaders: 
          'Content-Type': 'text/event-stream'
      
  );
  eventSource.onmessage = (event) => 
      console.log('Received event: ', event);
  ;

【问题讨论】:

因此,由于您没有向其发送任何内容,因此您的连接可能再次被负载均衡器中止?您可以在浏览器开发工具中查看此连接发生了什么。或者,您可以尝试在作业运行期间从服务器重复发送一些虚假数据,这样连接就不会关闭。 谢谢,现在我每 30 秒发送一些假数据,并且连接没有关闭。 【参考方案1】:

连接保持活动不起作用,因为连接上没有任何活动。

我的负载平衡器正在终止连接。

现在可以通过每 30 秒在连接上发送一些虚假数据并保持连接处于活动状态来解决此问题。

【讨论】:

以上是关于用于长时间运行过程的 Spring SSE的主要内容,如果未能解决你的问题,请参考以下文章

Spring 和 Hibernate 的长时间运行事务?

SQL Server 存储过程在第一次运行时需要很长时间

Spring REST - 经过较长的空闲时间后,第一次调用需要很长时间(5-10 秒)

Android AsyncTask 用于长时间运行的操作

Spring + Hibernate+ HikariCP:如何在进行长时间运行的 REST 调用时处理数据库连接?

用于长时间运行代码的 gevent 探查器