2017-03-16 10 views
2

私はspring 4.3.7.RELEASEを使用して、サーバー送信イベントを設定しています。また、@scheduled注釈を使用して2秒ごとにメッセージを送信しました。 ここにコントローラがあります。Spring Server送信イベント - ResponseBodyEmitterは既に設定されています

@Controller 
public class MySSEController { 
    private final SseEmitter sseEmitter = new SseEmitter(); 
    private int counter = 0; 

    @RequestMapping("/ssestream") 
    public SseEmitter getRealTimeMessageAction() throws IOException { 

     sseEmitter.send("MessageCounter : " + counter); 
     return sseEmitter; 
    } 

    @Scheduled(fixedDelay = 2*1000) 
    public void scheduledMsgEmitter() throws IOException 
    { 
     if(null != sseEmitter) { 
      sseEmitter.send("MessageCounter : " + ++counter); 
     } 
    } 

} 

私はこれをEclipseから直接Tomcat 9で実行しています。アプリケーションは2秒ごとにブラウザを起動し、メッセージをブラウザに送信します。しかし、しばらくするとメッセージの送信が止まり、Eclipseのコンソールで以下の例外が表示されます。

Mar 16, 2017 6:57:34 PM org.springframework.web.servlet.mvc.support.DefaultHandlerExceptionResolver handleAsyncRequestTimeoutException 
SEVERE: Async timeout for GET [/streaming-web/stream/ssestream] 
Mar 16, 2017 6:57:35 PM org.springframework.scheduling.support.TaskUtils$LoggingErrorHandler handleError 
SEVERE: Unexpected error occurred in scheduled task. 
java.lang.IllegalStateException: ResponseBodyEmitter is already set complete 
    at org.springframework.util.Assert.state(Assert.java:70) 
    at org.springframework.web.servlet.mvc.method.annotation.ResponseBodyEmitter.send(ResponseBodyEmitter.java:158) 
    at org.springframework.web.servlet.mvc.method.annotation.SseEmitter.send(SseEmitter.java:126) 
    at org.springframework.web.servlet.mvc.method.annotation.SseEmitter.send(SseEmitter.java:107) 
    at org.springframework.web.servlet.mvc.method.annotation.SseEmitter.send(SseEmitter.java:89) 
    at com.mycomp.test.controllers.MySSEController.scheduledMsgEmitter(MySSEController.java:25) 
    at sun.reflect.GeneratedMethodAccessor31.invoke(Unknown Source) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at org.springframework.scheduling.support.ScheduledMethodRunnable.run(ScheduledMethodRunnable.java:65) 
    at org.springframework.scheduling.support.DelegatingErrorHandlingRunnable.run(DelegatingErrorHandlingRunnable.java:54) 
    at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511) 
    at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:308) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(ScheduledThreadPoolExecutor.java:180) 
    at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:294) 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) 
    at java.lang.Thread.run(Thread.java:745) 

私には何か不足していますか?この問題を解決するのを手伝ってください。

+0

カスタムタイムアウトオプションでSseEmitterコンストラクタを試しましたか? – gvmani

+0

@gvmaniはい、あります。 '新しいSseEmitter(60000l)'を使用して、1分後に同じ例外が発生しました。ブラウザで受信した最後のメッセージは_ "MessageCounter:31" _ –

+0

こんにちは@Pete、あなたはこれの解決策を見つけましたか?私はあまりにも同じ問題に直面している、ソリューションを投稿してくださいありがとう、 –

答えて

2

正しい解決策であるかどうかはわかりません。

は、私は少し接続されているすべてのクライアントEarlier I was unable to deliver the same message to different clients connected to this stream この実装はIllegalStateExceptionをスローしませんで動作するように実装を変更しました。

import java.io.IOException; 
import java.util.HashSet; 
import java.util.Set; 

import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 

import org.springframework.scheduling.annotation.Scheduled; 
import org.springframework.stereotype.Controller; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter; 

@Controller 
public class MySSEController_Working { 

    private Set<SseEmitter> sseEmitters = new HashSet<SseEmitter>(); 
    private int messageCount = 0; 

    @RequestMapping("/ssestream") 
    public SseEmitter getRealTimeMessageAction(HttpServletRequest request, HttpServletResponse response) throws IOException { 

     final SseEmitter sseEmitter = new SseEmitter(); 

     sseEmitter.onCompletion(() -> { 
      synchronized (this.sseEmitters) { 
       this.sseEmitters.remove(sseEmitter); 
      } 
     }); 

     sseEmitter.onTimeout(()-> { 
      sseEmitter.complete(); 
     }); 

     // Put context in a map 
     sseEmitters.add(sseEmitter); 

     return sseEmitter; 
    } 

    @Scheduled(fixedDelay = 2*1000) 
    public void scheduledMsgEmitter() throws IOException 
    { 
     if(!sseEmitters.isEmpty()) 
      ++messageCount; 
     else 
      System.out.println("No active Emitters "); 

     System.out.println("Sent Messages : " + messageCount); 

     sseEmitters.forEach(emitter -> { 
      if (null != emitter) 
       try { 
        System.out.println("Timeout : "+ emitter.getTimeout()); 
        emitter.send("MessageCounter : " + messageCount); 
        emitter.complete(); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } 
     }); 
    } 
} 
+0

ありがとう、私はあなたの解決策を試してみましょう。 –

0

SseEmitter timeoutの単位はミリ秒で、60001は60秒です。これはセッションのタイムアウトであり、セッションのアクティビティの影響を受けません。

タイムアウトは、セッションの予想される期間(ミリ秒単位)に設定する必要があります。したがって、86400000(またはそれ以上)が完全に適切です。

関連する問題