Repository navigation
fix(core): @Scheduled 7개가 스레드 1개를 공유 + 스케줄러 생존 신호 없음 - #257
Merged
Merged
Conversation
꼬리질문 스위퍼를 붙이다(#256) 스케줄러 구조를 보고 발견했다. `@Scheduled` 가 7개인데 Spring Boot 기본 `spring.task.scheduling.pool.size` 는 **1** 이다. 전부 한 줄로 선다. ExpiredRefreshTokenSweeper 1일 ProcessedMessageSweeper 1일 AiRequestLogSweeper 1일 OrphanedObjectSweeper 15분 ← S3/MinIO 를 돈다 SessionTimeoutSweeper 5분 ← 면접 복구 StaleTranscriptionSweeper 2분 ← 면접 복구 StaleFollowupSweeper (#256) 2분 ← 면접 복구 뒤의 셋은 **멈춘 면접을 푸는 유일한 장치**다. 느린 작업 하나가 스레드를 잡으면 면접 복구가 통째로 멈춘다. 가장 유력한 후보는 OrphanedObjectSweeper 다. ## 1) 풀 크기 `${SCHEDULING_POOL_SIZE:4}`. 설정 한 줄이 지워져도 컴파일·테스트가 통과하고 운영에서도 장애 때까지 아무 증상이 없어서 SchedulingPoolSizeTest 로 지킨다. ## 2) S3 호출 상한 AWS SDK v2 기본값에는 **호출 전체 상한이 없다** — 소켓 타임아웃과 재시도뿐이다. 같은 S3Client 를 요청 스레드(업로드·프록시)와 스케줄러가 공유하므로, MinIO 가 느려지면 전자는 톰캣 스레드를, 후자는 스케줄러를 붙잡는다. apiCallTimeout 30초 / apiCallAttemptTimeout 10초를 건다. ## 3) 그래서 지금 돌고 있기는 한가 — 알 방법이 없었다 스위퍼들은 할 일이 없으면 로그를 남기지 않는다. 그래서 "돌았는데 대상이 없었다" 와 "아예 안 돌았다"를 구분할 수 없다. 운영 백엔드 로그를 통째로 뒤져도 sweeper 관련 줄이 **0건**이다. SchedulerHeartbeat 가 1분마다 타임스탬프만 갱신하고, 5분 넘게 멈추면 SchedulerHealthIndicator 가 DOWN 을 낸다(/api/system/health 의 scheduler). DB·네트워크를 건드리지 않는다 — 심장박동이 자기가 감시하는 문제(느린 I/O)로 막히면 안 된다. BACKUP 과 같이 **informational** 이라 aggregate 는 끌어내리지 않는다. 스케줄러가 멈춰도 면접·로그인·조회는 정상이다. 여기서 DOWN 은 "서비스가 죽었다"가 아니라 "고장 복구가 안 되고 있다"는 뜻이고, 섞으면 업타임 감시가 헛울린다.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
문제
@Scheduled가 7개인데 Spring Boot 기본spring.task.scheduling.pool.size는 1 이다.전부 한 줄로 선다.
뒤의 셋은 멈춘 면접을 푸는 유일한 장치다. 느린 작업 하나가 스레드를 잡으면 면접 복구가
통째로 멈춘다 — 그리고 아무도 모른다.
1) 풀 크기 → 4
${SCHEDULING_POOL_SIZE:4}. 설정 한 줄이 지워져도 컴파일·테스트가 통과하고 운영에서도장애가 날 때까지 아무 증상이 없다. 그래서
SchedulingPoolSizeTest가 CI 에서 대신 본다.2) S3 호출 상한
AWS SDK v2 기본값에는 호출 전체 상한이 없다 — 소켓 타임아웃과 재시도뿐이다. 같은
S3Client를 요청 스레드(업로드·프록시)와 스케줄러가 공유하므로, MinIO 가 느려지면 전자는톰캣 스레드를, 후자는 스케줄러를 붙잡는다.
apiCallTimeout30초 /apiCallAttemptTimeout10초를 건다. "느림"이 "멈춤"으로 번지지 않게 하는 것이 목적이다.
3) 지금 돌고 있기는 한가 — 알 방법이 없었다
스위퍼들은 할 일이 없으면 로그를 남기지 않는다. 그래서 "돌았는데 대상이 없었다"와
"아예 안 돌았다"를 구분할 수 없다. 운영 백엔드 로그를 통째로 뒤져도 sweeper 관련 줄이
0건이다:
SchedulerHeartbeat가 1분마다 타임스탬프만 갱신하고, 5분 넘게 멈추면SchedulerHealthIndicator가 DOWN 을 낸다 (/api/system/health의scheduler).DB·네트워크를 건드리지 않는다 — 심장박동이 자기가 감시하는 문제(느린 I/O)로 막히면 안 된다.
BACKUP과 같이 informational 이라 aggregate 는 끌어내리지 않는다. 스케줄러가 멈춰도면접·로그인·조회는 정상이다. 여기서 DOWN 은 "서비스가 죽었다"가 아니라 "고장 복구가 안 되고
있다"는 뜻이고, 섞으면 업타임 감시가 헛울린다.
검증
SchedulerHealthIndicatorTest5,SchedulingPoolSizeTest1,SystemHealthServiceTest에 informational 케이스 1 추가남은 것 (이 PR 범위 밖)
풀을 4로 늘려도 작업이 겹치면 여전히 밀린다. 지금 주기(2·5·15분)에서는 문제되지 않지만,
장기적으로는 무거운 작업(S3 순회)을 별도 executor 로 빼는 편이 맞다. 지금은 관측 수단을
먼저 만들어 두고 실제로 밀리는지 본다.