Неожиданная ошибка на конечной точке SSE в контроллере. Приложение Spring boot + angular 8 - PullRequest
0 голосов
/ 23 марта 2020

Я принимаю участие в разработке приложения Spring Boot + Angular 8, которое развертывается в облаке. Приложение Spring boot, приложение NG, а также сервер NGINX упакованы и построены с использованием docker -compose . Мы также используем dockerized PostgreSQL database.

Я работаю над функциональностью включения конечной точки SSE для получения текущего состояния установки. Статус извлекается из внешнего API, но в данном случае это не имеет значения. Проблема заключается только в асинхронной связи c между приложением Angular и приложением Spring при загрузке через конечную точку /install/status/{installationId}.

В финальной версии приложения. Я собираюсь получить статус установки Flux<InstallationStatus из getInstallationStatusStream метода. И для этого метода проблема, которую я собираюсь объяснить позже, все еще существует. Но для простоты я создаю простой Flux .

Вот код контроллера приложения Spring Boot:

@GetMapping(value = "/status/{installationId}", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
@Transactional
public Flux<InstallationStatus> installationStatus(@PathVariable String installationId,
                                                   @CookieValue(YDC_USER) String ydcUserCookieValue) {

    return Flux.just(InstallationStatus.EXECUTING, InstallationStatus.EXECUTING, InstallationStatus.SUCCESS).delayElements(
            Duration.ofMinutes(1)).log();
//        try {
//            return commerceInstallationService.getInstallationStatusStream(installationId, ydcUserCookieValue);
//        } catch (InstallationError installationError) {
//            return Flux.error(installationError);
//        }
    }

Итак, просто простой Flux. Я получаю его на Angular интерфейсе, используя этот код:

getInstallationStatus(installationId: string): void {
    this.eventSource = new EventSource(this.INSTALLATION_STATUS_ENDPOINT + '/' + installationId);
    this.eventSource.onmessage = event => this.onMessage(event);
    this.eventSource.onerror = error => {
      if (this.eventSource.readyState === 0) {
        console.log('The stream has been closed by the server.');
        this.eventSource.close();
      } else {
        console.error('EventSource error.');
        this.installationStatusSource.next(InstallationStatus.FAILURE);
      }
    };
  }

  onMessage(event: MessageEvent): void {
    const statusName = JSON.parse(event.data);
    switch (statusName) {
      case 'SUCCESS':
        this.installationStatusSource.next(InstallationStatus.SUCCESS);
        break;
      case 'EXECUTING':
        this.installationStatusSource.next(InstallationStatus.EXECUTING);
        break;
      case 'FAILURE':
        this.installationStatusSource.next(InstallationStatus.FAILURE);
        break;
    }
  }

И все работает нормально, но только в локальной среде (построенной также с использованием docker -композиции и с dockerized NGINX и база данных).

После развертывания в облаке я получаю странные ошибки от nio . Что указывает на то, что проблема существует под Spring Boot на нижнем уровне. Вот журналы на уровне DEBUG:

LOGS

Я искал высоко и низко в Интернете, и по этому поводу нет особой информации. Основная проблема в том, что эта ошибка даже не отображается на ExceptionHandler в Spring. И что хуже как-то HikariPool показывает, что соединение с базой данных не было закрыто после этой ошибки! И интерфейс никогда не уведомляется о том, что этот поток закрыт должным образом.

Что здесь происходит? Может ли это быть как-то из конфигурации NGINX? Я добавил конфиги для NGINX для правильной обработки SSE :

{...}
                #SSE aggregating issue:
            chunked_transfer_encoding off;
            proxy_buffering off;
            proxy_cache off;

            #SSE connection closing issue
            proxy_set_header Connection keep-alive;
            proxy_connect_timeout 3600;
            proxy_send_timeout 3600;
            proxy_read_timeout 3600;
            keepalive_timeout 3600;
    }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...