2016-07-29 16 views
0

多くの並列要求を処理する非同期REST APIがあります。いくつかの現時点で50件の要求(この数字は常に多少異なります)周りの処理を終えた後、私は次のエラーメッセージ・スタックを取得:java.lang.IllegalStateException:非同期REST API

java.lang.IllegalStateException: Cannot forward after response has been committed 
    at org.apache.catalina.core.ApplicationDispatcher.doForward(ApplicationDispatcher.java:321) ~[tomcat-embed-core-8.5.4.jar:8.5.4] 
    at org.apache.catalina.core.ApplicationDispatcher.forward(ApplicationDispatcher.java:311) ~[tomcat-embed-core-8.5.4.jar:8.5.4] 
    at org.apache.catalina.core.StandardHostValve.custom(StandardHostValve.java:395) [tomcat-embed-core-8.5.4.jar:8.5.4] 
    at org.apache.catalina.core.StandardHostValve.status(StandardHostValve.java:254) [tomcat-embed-core-8.5.4.jar:8.5.4] 
    at org.apache.catalina.core.StandardHostValve.throwable(StandardHostValve.java:349) [tomcat-embed-core-8.5.4.jar:8.5.4] 
    at org.apache.catalina.core.AsyncContextImpl.setErrorState(AsyncContextImpl.java:412) [tomcat-embed-core-8.5.4.jar:8.5.4] 
    at org.apache.catalina.connector.CoyoteAdapter.asyncDispatch(CoyoteAdapter.java:158) [tomcat-embed-core-8.5.4.jar:8.5.4] 
    at org.apache.coyote.AbstractProcessor.dispatch(AbstractProcessor.java:222) [tomcat-embed-core-8.5.4.jar:8.5.4] 
    at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:53) [tomcat-embed-core-8.5.4.jar:8.5.4] 
    at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:785) [tomcat-embed-core-8.5.4.jar:8.5.4] 
    at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1425) [tomcat-embed-core-8.5.4.jar:8.5.4] 
    at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49) [tomcat-embed-core-8.5.4.jar:8.5.4] 
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [na:1.8.0_91] 
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [na:1.8.0_91] 
    at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) [tomcat-embed-core-8.5.4.jar:8.5.4] 
    at java.lang.Thread.run(Thread.java:745) [na:1.8.0_91] 

2016-07-29 16:36:28.505 ERROR 7040 --- [nio-8090-exec-2] o.a.c.c.C.[Tomcat].[localhost]   : Exception Processing ErrorPage[errorCode=0, location=/error] 

私は、このエラーで一日strugellingた...問題は、私がいることですその起源を理解していない。私それはExecuterとは何かを持っているので、次のように私はそれを構成しても:

@Configuration 
@SpringBootApplication 
@EnableAsync 
public class AppConfig { 
    @Bean 
    public javax.validation.Validator localValidatorFactoryBean() { 
     return new LocalValidatorFactoryBean(); 
    } 

    @Bean 
    public Executor getAsyncExecutor() { 
     ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor(); 
     executor.setCorePoolSize(500); 
     executor.setMaxPoolSize(1000); 
     executor.setQueueCapacity(1000); 
     executor.setThreadNamePrefix("MyExecutor-"); 
     executor.initialize(); 
     return executor; 
    } 

    public static void main(String[] args) { 
     SpringApplication.run(AppConfig.class, args); 
    } 

} 

しかし、問題がまだ存在します。誰かが私にこの問題の理由とその対処方法を説明できるなら、大いに感謝します。

UPDATE:

ホワイトレーベルのエラーページ

このアプリケーションは/エラーのための 明示的なマッピングを持っていない、あなたはこれを見ているように、次のエラーが返され、特に

フォールバック。

金7月29日16時36分28秒は、CEST 2016Thereは、これはコードです

予期しないエラーが利用可能(タイプ=内部サーバー エラー、状況= 500).NOのメッセージでしたCONTROLLER

@RestController 
@RequestMapping("/test") 
public class SController { 

    private static long maxConcurrentRequests = 0; 

    @Autowired 
    Validator validator; 

    @Autowired 
    SAnalyzer analyzer; 

    /** 
    * Non-blocking processing 
    * @param docId 
    * @param document 
    * @return 
    */ 
    @RequestMapping(value = "/{docId}/getAnnotation", method = RequestMethod.GET) 
    public DeferredResult<Annotations> getAnnotation(@PathVariable String docId, 
                @RequestParam(value = "document", defaultValue = "{'id':'1','title':'bla-bla','abstract':'bla-bla','text':'bla-bla'}") String document) { 

       LOGGER.info("Logging output to console"); 
    long reqId = lastRequestId.getAndIncrement(); 
    long concReqs = concurrentRequests.getAndIncrement(); 

    LOGGER.info("{}: Start non-blocking request #{}", concReqs, reqId); 

    SRequest srequest = new SRequest(SRequest.TYPE_ANNOTATION, docId, document, 1); 
    this.validateRequest(srequest); 

    // Initiate the processing in another thread 
    DeferredResult<Annotations> response = new DeferredResult<>(); 
    analyzer.getAnnotation(reqId, concurrentRequests, srequest,response); 

    LOGGER.info("{}: Processing of non-blocking request #{} leave the request thread", concReqs, reqId); 

    // Return to let go of the precious thread we are holding on to... 
    return response; 

    } 

    private void validateRequest(SRequest request) { 
     DataBinder binder = new DataBinder(request); 
     binder.setValidator(validator); 
     binder.validate(); 
     if (binder.getBindingResult().hasErrors()) { 
      throw new BadSysRequestException(binder.getBindingResult().toString()); 
     } 
    } 

} 

@ResponseStatus(HttpStatus.BAD_REQUEST) 
class BadSysRequestException extends RuntimeException { 

    public BadSysRequestException(String message) { 
     super("Bad request '" + message + "'."); 
    } 
} 

TASK

@Async 
    @Override 
    public void getAnnotation(long reqId, AtomicLong concurrentRequests, SRequest request, DeferredResult<Annotations> deferredResult) 
    { 
     this.deferredResultAnnotations = deferredResult; 

     this.concurrentRequests = concurrentRequests; 
     long concReqs = this.concurrentRequests.getAndDecrement(); 
     if (deferredResult.isSetOrExpired()) { 
      LOGGER.warn("{}: Processing of non-blocking request #{} already expired {}", concReqs, reqId, request.getDocument()); 
     } else { 
      // result = make some heavy calculations 

      deferredResultAnnotations.setResult(result); 
      LOGGER.info("{}: Processing of non-blocking request #{} done {}", concReqs, reqId, request.getDocument()); 
     } 

    } 
+0

可能な複製:http://stackoverflow.com/questions/22743803/servlet-with-java-lang-illegalstateexception-cannot-forward-after-response-has –

+0

@PiotrWilkin:私は 'forward'を使用していません。コードスニペットを一瞬で投稿します。 – HackerDuck

+0

@PiotrWilkin:スレッドを更新しました。あなたが指定したスレッドでは、エラーの理由は、 '応答がクライアントにコミットされる前にフォワードが呼び出されます'として指定されます。しかし、私は自分のコードで 'forward'をどこで使うのか分かりません...特に、Xリクエストがうまく処理され、その時だけ問題が出てくる理由を知ることができません。 – HackerDuck

答えて

1

さて、CoyoteAdapterソースからの関連フラグメントは読む:

 if (status==SocketEvent.TIMEOUT) { 
      if (!asyncConImpl.timeout()) { 
       asyncConImpl.setErrorState(null, false); 
      } 
     } 

だから、それは適切に処理されなかったソケットタイムアウトです。

+0

ありがとうございました。私は今それを確認します。私はScalaから次のようにリクエストを送信します: '応答:HttpResponse [String] = Http(url).timeout(connTimeoutMs = 10000、readTimeoutMs = 20000000).param(param、paramValue).asString'おそらく 'connTimeoutMs'を変更する必要があります。それを無限にするのは良い考えですか? – HackerDuck

+0

'connTimeoutMs'と' readTimeputMs'( 'connTimeoutMs = 1000000000、readTimeoutMs = 2000000000')をインクリメントしましたが、このエラーはほぼ同じ瞬間に再び現れます。だから、ソケットのタイムアウトを指定すべき場所があります。いくつかのコンフィグでREST API側でそれを明示すべきですか? – HackerDuck

関連する問題