⚠️ hutdown phase 2147481599 ends with 1 bean still running after timeout of 30000ms

이은미·2024년 4월 29일
0
2024-04-29T12:10:45.012Z  INFO 11975 --- [nawabali] [ionShutdownHook] o.s.c.support.DefaultLifecycleProcessor  : Shutdown phase 2147481599 ends with 1 bean still running after timeout of 30000ms: [webServerStartStop]

에러 단계가 INFO여서 문제가 되지는 않았지만 예상치 못한 작업이나 리소스 누출로 인해 발생할 수도 있는 에러를 예방하는 차원에서 추가 수정을 했다.

이 로그는 스프링 애플리케이션이 종료될 때 남아 있는 빈이 있는 경우에 발생한다. 보통은 애플리케이션이 종료되는 동안에도 여전히 실행 중인 작업이나 백그라운드 스레드 등이 있는 경우에 이러한 경고가 표시됩니다.
종료가 된 후에도 hearbeat로 보내는 시간(30000ms)이 남아있어서 경고가 표시됐던것 같다.
연결이 끊어진 클라이언트의 SseEmitter를 emitters 맵에서 제거하는 부분에서 문제가 발생할 수 있어서 수정을 했다.

일반적으로 Java에서는 컬렉션을 반복하면서 수정하는 것은 안전하지 않고 클라이언트의 연결이 끊어졌을 때 이를 안전하게 제거해야 한다.그래서 Iterator를 이용하기로 했다.
Iterator를 사용하면 컬렉션을 반복하면서 안전하게 제거할 수 있고 ConcurrentModificationException을 방지하는 데 도움이 된다.

	@Scheduled(fixedRate = 30000) 
    public void sendHeartbeat() {

        Iterator<Map.Entry<Long, SseEmitter>> iterator = emitters.entrySet().iterator();
        while (iterator.hasNext()) {
            Map.Entry<Long, SseEmitter> entry = iterator.next();
            Long userId = entry.getKey();
            SseEmitter emitter = entry.getValue();
            try {
                emitter.send(SseEmitter.event().comment("heartbeat")); 
                log.info("하트비트 보내기");
            } catch (IOException e) {
                emitter.completeWithError(e);
                iterator.remove(); // 안전하게 제거
                log.info("연결이 끊어져 삭제됨: userId = {}", userId);
            }
        }
    }
profile
파이팅 해야지

0개의 댓글