728x90 전체 글18 npm ci와 npm install 차이 — 속도가 아니라 락 파일을 대하는 태도다 npm ci와 npm install의 차이는 속도가 아니라 락 파일을 대하는 태도다. npm install은 필요하면 package-lock.json을 고쳐 쓰고, npm ci는 한 글자도 안 고치고 안 맞으면 멈춘다.그래서 CI에서는 npm ci가 맞다. 커밋된 락 파일과 다른 트리가 설치되는 일이 구조적으로 불가능하기 때문이다.대신 조용히 발목을 잡는 설정이 하나 있다. NODE_ENV=production이 먼저 잡혀 있으면 devDependencies가 설치되지 않는다. 빌드 도구가 거기 있으면 설치는 성공하고 빌드가 실패한다.한 줄로 갈리는 지점npm install은 "package.json을 만족하는 트리를 만든다"에 가깝고, npm ci는 "락 파일에 적힌 트리를 그대로 재현한다"에 가깝다.그.. 2026. 9. 14. Spring readOnly 트랜잭션을 리더로 보내면 생기는 read-after-write 문제 결제를 취소하고 저장 성공까지 떴는데, 화면이 다시 그려지면 취소 이전 상태가 보였다. 새로고침하면 정상이고 DB도 정상이었다. 화면만 틀렸다.원인은 @Transactional(readOnly = true)를 리더 복제본으로 보내는 라우팅이었다. 저장 직후의 조회가 복제가 따라오기 전의 리더를 읽은 것이다.readOnly = true는 "읽기만 한다"가 아니라 "이 결과는 조금 낡아도 된다"는 선언이다. 방금 바꾼 것을 다시 보는 화면에는 붙이면 안 된다.구조부터이 앱은 읽기와 쓰기 DB를 나눠 쓴다. Spring의 AbstractRoutingDataSource로, 현재 트랜잭션이 읽기 전용이면 리더 복제본으로, 아니면 라이터로 보낸다.protected Object determineCurrentLooku.. 2026. 9. 13. MySQL 집계 쿼리를 요약 테이블로 빼면서 정확도를 안 버리는 법 회원 등급 대상자를 세는 화면이 큰 점포에서 5.6초 걸렸다. 조건을 바꿀 때마다 몇 년치 구매 이력을 처음부터 다시 더하기 때문이다.산식은 그대로 두고 결과만 미리 담는 요약 테이블로 뺐다. 4,932ms가 508ms가 됐다.핵심은 속도가 아니라 BASE_DATE 컬럼이다. 과거는 요약본, 오늘은 실시간으로 나누면 정확도를 안 버리면서 범위만 줄일 수 있다.왜 느린가회원 등급을 자동으로 매기는 화면이 있다. "누적 결제금액이 얼마 이상인 회원을 VIP로 올린다" 같은 조건을 걸면 대상자 수를 보여준다.산식이 이렇다.일반 서비스 → 상품 정보 테이블의 정가그 외(패키지·이벤트·쿠폰) → 이벤트 상품 정보 테이블의 정가패키지 한 건이 항목 수만큼 부풀지 않도록 예약 단위로 먼저 접는다그걸 회원별로 합산한 .. 2026. 9. 13. 장기 액세스 키 대신 브리지 프로필로 Terraform 돌리기 ~/.aws/credentials에 든 장기 액세스 키의 문제는 유출 가능성 자체가 아니다. 유출을 알아챌 방법이 없다는 것이다. 만료가 없으니 계속 통하고, CloudTrail에는 사람이 아니라 IAM 사용자 이름만 남으며, 회수하려면 그 키를 쓰는 사람 전원이 다시 설정해야 한다. 그래서 사람에게는 키를 주지 않기로 했다. 그리고 이 편에서 제일 아찔했던 건 정책이 아니라 검증 도구가 틀린 것이었다.왜 없앴나장기 키의 문제를 하나씩 보면 이렇다.만료가 없으니 계속 통한다CloudTrail에는 사람이 아니라 그 IAM 사용자 이름만 남는다. 누가 썼는지 모른다회수하려면 그 키를 쓰는 사람 전원이 다시 설정해야 한다. 한 사람만 뺄 수가 없다세 번째가 실무에서 제일 크다. 사람 하나가 나갈 때 키를 못 .. 2026. 9. 11. MySQL 타임존 설정, TIMESTAMP와 DATETIME이 다르게 움직인다 MySQL에서 시간이 9시간 어긋날 때 흔히 서버 타임존 하나만 본다. 그런데 갈리는 지점은 서버·세션·JDBC 세 곳이고, 셋이 서로 다른 값을 들고 있을 수 있다.더 고약한 건 TIMESTAMP와 DATETIME이 다르게 움직인다는 것이다. TIMESTAMP만 세션 타임존으로 변환되고 DATETIME은 저장된 그대로 나온다.그래서 증상이 "전부 9시간 밀림"이 아니라 "어떤 값은 밀리고 어떤 값은 안 밀림"으로 나타난다. 이게 원인 추적을 어렵게 만든다.컬럼 타입에 따라 다르게 움직인다이걸 먼저 알아야 나머지가 읽힌다. MySQL 문서가 명확하게 갈라 놓는다.TIMESTAMP — 저장할 때 세션 타임존에서 UTC로 바꿔 넣고, 읽을 때 UTC에서 세션 타임존으로 되돌린다. 세션 타임존이 바뀌면 같은 .. 2026. 9. 10. Flyway MySQL 프로시저 syntax error — SQL이 아니라 파서가 문제였다 Flyway로 MySQL 저장 프로시저를 넣었더니 syntax error near '' at line 80으로 배포가 멈췄다. 80번 줄은 멀쩡했고, 그 줄만 떼어 DB에서 직접 실행하면 잘 만들어졌다.원인은 SQL이 아니라 Flyway 8.0의 MySQL 파서였다. END REPEAT를 프로시저의 끝으로 잘못 읽고 그 앞에서 문장을 잘라 버린다.에러는 DB가 내지만 원인은 파서에 있다. 그래서 SQL을 아무리 봐도 안 보인다.어떤 구조에서 나나스키마 변경을 Flyway로 관리한다. 앱이 뜰 때 미적용 마이그레이션을 순서대로 자동 실행하고, 이력은 FLYWAY_SCHEMA_HISTORY에 남는다. 별도 CLI를 돌리지 않는다.테이블만 다룰 때는 문제가 없었다. 저장 프로시저와 이벤트를 넣으면서 겪은 것들.. 2026. 9. 9. 이전 1 2 3 다음 728x90