Spring Boot Controller POST с входным потоком, время от времени отправляющим TCP RST

сценарий

В нашем Spring boot application (версия - 1.5.10), есть контроллер, который получает двоичное содержимое (скажем, слово документ .docx содержимое) и сохраняет его в файловой системе. В нормальных случаях работает нормально. Но есть случай использования бизнеса, где

  • мы бросаем 409 http код статуса,
  • установить заголовок приложения и
  • мы не храним содержимое (мы не обрабатываем входной поток).

проблема

В приведенном выше бизнес-сценарии встроены tomcat/jetty иногда (не всегда) отправляет сброс соединения (TCP RST) соединения TCP сразу после возврата 409 код ответа. Опять же, это не всегда так, но когда мы отправляем сброс соединения, обратный прокси-сервер (в нашем случае версия веб-сервера apache ~ 2.4.10) завершает нас, выдавая клиенту 502.

представление дампа tcp, содержащее пакеты сброса

Мы не можем понять, почему из сервиса отправляется сброс соединения.

Участники взаимодействия

| Клиент (клиент API, а не браузер - на внешней основе)| ->

| Обратный прокси / балансировщик нагрузки (Apache)| ->

| Spring boot Service (на основе Tomcat / Jetty)|

Интересные фрагменты кода

// This is the controller related code

@PostMapping(value = CONTENTS,consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
public ResponseEntity save(@PathVariable(FILE_ID_PATH_PARAM_NAME) FileId fileId, @RequestHeader(value = "X-Some-Lock") String lock, InputStream inputStream) {
    try {
        Optional<String> lockId = Optional.ofNullable(lock);
        documentService.checkLock(fileId, lockId, accessTokenContext); // This is where lock checking happens
        // If lock check does not cause any problems then save happens in the below call
        String version = documentService.save(fileId, inputStream, accessTokenContext); 
        LOG.info("WOPI - method - save, Current File Version : {} ", version);
        return ResponseEntity.ok().headers(header(version)).build();
    } finally {
        IOUtils.closeQuietly(inputStream);
    }
}


// This the global exception handler related code.

@ExceptionHandler(LockMismatchException.class)
public void handleLockMismatchException(LockMismatchException e, HttpServletResponse response) throws IOException {
    LOG.error(e.getMessage(), e);
    // We did this to figure out if there is any difference between doing this or going the ResponseEntity
    // route. Both of them seem equivalent and don't work for us
    response.addHeader(LOCK.header(), e.existingLockId());
    response.sendError(CONFLICT.value(), CONFLICT.getReasonPhrase());
}

Что мы знаем и / или пытались (и не работали)

  • Эта проблема не зависит от сервера. Мы столкнулись с той же проблемой, независимо от использования jetty or tomcat в качестве встроенного сервера.

  • Мы пытались установить maxSwallowSize в -1 чтобы разрешить обработку прерванных загрузок, но это не помогло.

  • Мы попытались отключить механизм http keep alive, чтобы проверить, вызывает ли это это, установив "maxKeepAliveRequests"чтобы 1,
  • Мы попытались удалить специальный заголовок нашего приложения и просто отправить статус, что также не помогло.

Я не могу прикрепить tcpdump мы захватили здесь. Если кто-то заинтересован, мы можем отправить его непосредственно им.

Любые указатели / предложения о том, как мы можем решить эту проблему, будут очень полезны.

0 ответов

Другие вопросы по тегам