Я принимаю участие в разработке приложения 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;
}