SseEmitter broken pipe

    使用SseEmitter進行日誌推送時,後臺出現 broken pipe 錯誤,排查發現是瀏覽器在訂閱打開SseEmitter請求連接時,會在一定時間內多次發起請求,但由於代碼中new SseEmitter後將實例保存起來,請求會查詢實例是否存在,如果存在則取出,但下次請求瀏覽器傳遞的是新的 EventSource,但後臺存的是舊實例,導致406錯誤。

    解決辦法:每次訂閱都將保存的實例移除後重新創建;

    問題:

org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe

	at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:299)

	at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:262)

	at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:118)

	at sun.nio.cs.StreamEncoder.implFlush(StreamEncoder.java:297)

	at sun.nio.cs.StreamEncoder.flush(StreamEncoder.java:141)

	at java.io.OutputStreamWriter.flush(OutputStreamWriter.java:229)

	at org.springframework.util.StreamUtils.copy(StreamUtils.java:124)

	at org.springframework.http.converter.StringHttpMessageConverter.writeInternal(StringHttpMessageConverter.java:110)

	at org.springframework.http.converter.StringHttpMessageConverter.writeInternal(StringHttpMessageConverter.java:44)

	at org.springframework.http.converter.AbstractHttpMessageConverter.write(AbstractHttpMessageConverter.java:227)

	at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler$HttpMessageConvertingHandler.sendInternal(ResponseBodyEmitterReturnValueHandler.java:191)

	at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitterReturnValueHandler$HttpMessageConvertingHandler.send(ResponseBodyEmitterReturnValueHandler.java:184)

	at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter.sendInternal(ResponseBodyEmitter.java:189)

	at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter.send(ResponseBodyEmitter.java:183)

	at org.springframework.web.servlet.mvc.method.annotation.SseEmitter.send(SseEmitter.java:133)

	at org.springframework.web.servlet.mvc.method.annotation.SseEmitter.send(SseEmitter.java:116)

	at org.springframework.web.servlet.mvc.method.annotation.SseEmitter.send(SseEmitter.java:95)

	at com.southgis.ispatial.dag.controller.DagController.subscribe(DagController.java:771)

	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)

	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)

	at java.lang.reflect.Method.invoke(Method.java:498)

	at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190)

	at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138)

	at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104)

	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892)

	at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797)

	at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87)

	at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039)

	at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942)

	at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005)

	at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897)

	at javax.servlet.http.HttpServlet.service(HttpServlet.java:634)

	at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:882)

	at javax.servlet.http.HttpServlet.service(HttpServlet.java:741)

	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:231)

	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)

	at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53)

	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)

	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)

	at org.springframework.web.filter.RequestContextFilter.doFilterInternal(RequestContextFilter.java:99)

	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)

	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)

	at org.springframework.web.filter.FormContentFilter.doFilterInternal(FormContentFilter.java:92)

	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)

	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)

	at org.springframework.web.filter.HiddenHttpMethodFilter.doFilterInternal(HiddenHttpMethodFilter.java:93)

	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)

	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)

	at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:200)

	at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107)

	at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)

	at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)

	at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:200)

	at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)

	at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:490)

	at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:139)

	at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:92)

	at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:74)

	at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343)

	at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:408)

	at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)

	at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:836)

	at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1747)

	at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)

	at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1149)

	at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:624)

	at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)

	at java.lang.Thread.run(Thread.java:748)

    代碼:

    @GetMapping(value = "xxx/subscribe")
    public SseEmitter subscribe(@RequestParam(name = "instId", required = false) Long instId) {
        Map<Long, SseEmitter> sseCache = SseParamsUtil.getSseCache();
        sseCache.remove(instId);
        SseEmitter sseEmitter = new SseEmitter(0L);
        sseCache.put(instId, sseEmitter);
        try {
            if (sseEmitter != null) {
                sseEmitter.send("EventSource start");
            }
        } catch (IOException e) {
            e.printStackTrace();
        }
        // 超時回調 觸發
        sseEmitter.onTimeout(() -> sseCache.remove(instId));
        sseEmitter.onError((throwable -> System.out.println(throwable)));
        // 結束之後的回調觸發
        sseEmitter.onCompletion(() -> System.out.println("sss推送結束!!!"));
        return sseEmitter;
    }
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章