
front-end 추가 설정
: EventSourcePolyfill 설치
: 45초 -> 60분으로 설정
// sse function
const sse = () => {
console.log("permission", Notification.permission);
const eventSource = new EventSourcePolyfill(
`${process.env.REACT_APP_API_URL}/alarm`,
{
headers: {
accessToken: `Bearer ${accessToken}`,
},
}
);
eventSource.addEventListener("sse", async (event) => {
const data = JSON.parse((event as MessageEvent).data);

로컬에서는 원활하게 작동하는데
서버에 올리기만 하면 오작동해서 로그를 찍어봤더니
client가 alarm을 막았다.
2023-10-04 05:13:10.014 INFO 1 --- [ scheduling-1] com.stn.hpdp.service.alarm.AlarmService : SSE 연결
오류 발생
org.apache.catalina.connector.ClientAbortException: java.io.IOException: Broken pipe
at org.apache.catalina.connector.OutputBuffer.doFlush(OutputBuffer.java:309) ~[tomcat-embed-core-9.0.79.jar!/:na]
at org.apache.catalina.connector.OutputBuffer.flush(OutputBuffer.java:271) ~[tomcat-embed-core-9.0.79.jar!/:na]
at org.apache.catalina.connector.CoyoteOutputStream.flush(CoyoteOutputStream.java:120) ~[tomcat-embed-core-9.0.79.jar!/:na]
at
1. request 후 response 기다리기
: Client에서 보낸 데이터를 받고 리턴할 때 까지 응답을 기다리도록 설정
2. Exception 무시하기
: Client가 비정상적인 종료를 했을시 Broken pipe signal이 발생하고
Client의 종료를 서버에서 제어할 수 없기 때문에 해당 시그널을 무시하게 해준다.
3. 중복 요청 막기
: 연속적인 버튼 클릭을 방지하거나 execption 처리 부분에서 오류를 뱉지 않도록 처리한다.
back-end controller -> AuthenticationPrincipal 추가
@GetMapping(produces = "text/event-stream") // produces = MediaType.TEXT_EVENT_STREAM_VALUE
public SseEmitter alarm(@AuthenticationPrincipal UserDetails userDetails,
@RequestHeader(value = "Last-Event-ID", required = false, defaultValue = "") String lastEventId,
HttpServletResponse response) {
return alarmService.alarm(userDetails, lastEventId, response);
}
back-end Alarm service -> header 추가
response.setHeader("X-Accel-Buffering", "no"); // NGINX PROXY 에서의 필요설정 불필요한 버퍼링방지
response.setHeader("Connection", "keep-alive");
response.setHeader("Cache-Control", "no-cache");
emitter exception 무시
try {
emitter.send(SseEmitter.event()
.id(eventId)
.name("sse")
.data(data));
} catch (IOException exception) {
if (exception.getMessage().contains("Broken pipe")) {
log.warn("SSE 연결이 끊어짐. 무시됨.", exception); // 경고 메시지로 로그를 기록
} else {
log.info("SSE 연결 오류 발생", exception);
emitterRepository.deleteById(emitterId);
throw new CustomException(SSE_CONNECTED_FAIL);
}
}
nginx 설정 추가
location /api {
proxy_pass [http://127.0.0.1:8080](http://127.0.0.1:8080/);
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header Host $http_host;
proxy_set_header Connection '';
proxy_http_version 1.1;
proxy_buffering off;
chunked_transfer_encoding off;
이렇게 설정해도 종종 client가 pipe를 끊어서
더미 데이터가 프론트에서 종종 확인되고 백엔드에서는 "SSE 연결이 끊어짐. 무시됨" 설정해준 로그가 계속 확인 되었다.
나중에 설정할 것들 :
아마 백엔드에서 더미를 시간마다 보내줘서 연결이 끊기지 않도록 조취를 취해줘야 할거 같다.
그리고 alarm 서비스가 백엔드 스케쥴링하고 트랜잭션으로 연결되어 있어서 로직을 조금 더 수정해야 할거 같다.