얼쑤의 백엔드는 운영에서 ops 프로필로 실행했습니다. 이 프로필에서는 앱이 이미 만들어진 DB에 연결하고, 스키마 변경은 별도 작업에서 적용합니다. 업무 API를 켜기 전의 구성을 확인해 보니 약관을 비롯한 업무 컨트롤러와 서비스가 db 프로필에만 등록돼 있었습니다. 프로세스가 기동해도 ops로 뜬 컨텍스트에는 약관 요청을 받을 컨트롤러가 없었습니다.

업무 빈과 마이그레이션 분리

처음에는 두 프로필을 함께 켜면 업무 빈도 만들 수 있다고 생각했습니다. 하지만 당시 db는 Flyway를 켰고 ops는 껐습니다. 두 프로필에 같은 설정 키가 있으면 뒤에 지정한 프로필의 값이 적용됩니다. 순서를 바꾸는 것만으로 운영 앱이 기동할 때 마이그레이션을 실행할 수 있는 구성이었습니다.

저는 업무 빈의 생성 조건을 @Profile("db | ops")로 넓혔습니다. 운영에서도 업무 코드를 조립할 수 있도록 MyBatis 매퍼 설정을 ops에 추가하고 DB 연결의 세션 시간대를 UTC로 맞췄습니다. ops의 Flyway 설정은 계속 꺼 두었습니다. 이렇게 하면 운영 실행에 필요한 빈과 DB 스키마 변경의 시작 시점을 각각 제어할 수 있습니다.

실행할 일당시 운영 프로필의 선택
약관과 업무 API 조립ops에서도 업무 빈과 매퍼를 등록합니다.
DB 연결과 쿼리이미 준비된 DB에 연결하고 세션 시간대를 UTC로 맞춥니다.
스키마 변경앱 시작 시 Flyway는 끄고 별도 적용 시점을 둡니다.

업무 API를 켤 때 같이 확인한 설정

헬스체크만 맡던 시기의 연결 풀 상한은 3개였습니다. 업무 API와 녹음 업로드 만료 작업이 같은 풀을 쓰게 되면서 상한을 10개로 늘렸고, 연결을 빌리는 대기 한도는 2초였습니다. 이 숫자는 운영 프로필의 설정값입니다. 변경 뒤 동시에 사용한 연결 수는 따로 측정하지 않았습니다.

업무 빈을 켜면서 인증번호에 쓰는 HMAC 키도 확인해야 했습니다. 설정이 비어 있으면 앱은 기동하고 인증번호 발송과 확인 요청만 503으로 응답하도록 바꿨습니다. 값이 들어왔는데 형식이 틀리면 시작할 때 오류를 내는 규칙은 유지했습니다. 테스트에는 공통 설정으로 키가 들어 있어, 운영과 같은 누락 조건을 만들기 위해 해당 테스트에서만 빈 문자열로 덮었습니다.

키를 뺀 단위 테스트에서는 인증번호의 해시 생성과 비교가 실패했고, 키 없이 계산하는 토큰의 SHA-256 해시는 기대값과 일치했습니다. 같은 설정이 사용되더라도 실제로 키를 읽는 기능만 제한할 수 있었습니다. 녹음 저장소도 연결 설정이 없으면 사용 불가 구현을 등록합니다. DB 통합 검사에서 이 구현이 등록됐고, 별도의 업로드 테스트에서는 저장 실패가 503으로 전달됐습니다.

예약 실행을 제어하는 별도 설정

녹음 업로드 만료 작업은 db와 ops에서 빈으로 등록하고, @Scheduled 메서드를 찾아 주기적으로 실행하는 설정은 별도로 뒀습니다. 통합 테스트처럼 같은 DB를 쓰면서 주기 작업을 막아야 하는 경우에는 eolssu.scheduling.enabled=false로 예약 실행만 끌 수 있습니다.

ApplicationContextRunner로 예약 실행 설정만 올려 후처리기 수를 셌습니다. db와 ops는 기본 설정에서 각각 1개, 스위치를 끄면 각각 0개였습니다. 프로필을 지정하지 않은 경우도 0개였습니다. 이 검사는 예약 실행 설정이 활성화되는 조건을 확인합니다. 만료 작업이 실제로 돌아 DB의 행을 바꾸는지는 별도의 검증 범위입니다.

약관 200과 Flyway 빈 0개

수정 전 운영 프로필 회귀 검사는 업무 컨트롤러를 찾지 못했습니다. 수정 후에는 임시 MySQL에 앱 바깥에서 마이그레이션을 먼저 적용하고, ops만 지정한 웹 서버에 실제 HTTP 요청을 보냈습니다. 세 가지를 함께 확인했습니다.

확인 대상관찰 결과
약관 조회HTTP 200, 본문의 성공 표시 확인
MySQL 세션 시간대+00:00
앱 컨텍스트의 Flyway 빈0개

DB와 인증번호 키를 모두 준비하지 않은 별도 기동 검사에서는 업무 컨트롤러와 매퍼가 등록됐고, liveness는 200, readiness는 503이었습니다. 격리 DB 테스트에서는 업무 API를 켠 상태에서 UTC로 DB에 연결하고 Flyway 빈은 생성하지 않는 구성을 확인했습니다. 실제 운영 교체와 약관 응답 확인 이후에는 마이그레이션의 실행 위치와 롤백 조건을 배포 작업으로 옮겼습니다. Flyway 선실행과 배포 롤백