[TIL-260722] 검증 재시도 API를 만들다 발견한 동시성 문제와 비관적 락으로 해결한 과정
·
Backend/DB
우리 서비스는 콘텐츠를 등록하면 백그라운드 비동기 워커가 AI 검증을 수행하고, 프론트엔드는 폴링(Polling)으로 검증 상태를 주기적으로 조회한다. 검증이 실패한 경우에는 사용자가 '재시도(Retry)' 버튼을 눌러 다시 검증을 요청할 수 있도록 API를 추가했다. 처음엔 단순한 API라고 생각했다. 기존 검증이 진행 중인지 확인하고, 아니라면 새로운 PENDING 이력을 만들고 검증 이벤트를 발행하면 끝이라고 생각했다. 그런데 구현을 마치고 다시 코드를 보니, 사용자가 버튼을 여러 번 누르는 순간 동시성 문제가 생길 수 있다는 걸 발견했다.1. 처음 구현은 이렇게 생겼다재시도 API의 역할은 단순하다.POST /api/contents/{contentId}/retry현재 검증이 진행 중인지 확인한다...
[TIL-260721] Swagger로는 보이지 않았던 검증 파이프라인의 버그들을 잡아낸 하루
·
Backend/Architecture & Design
1. Swagger로 호출만 해보고 끝내려 했는데콘텐츠 적합성 검증 파이프라인을 다 만들고 나서, Swagger로 실제 콘텐츠를 몇 개 등록해 보면서 잘 동작하는지 확인하기로 했다.POST /api/contents → GET /api/contents/{contentId}/validation계획은 단순했다. 몇 개 등록해보고, 응답이 PASSED/REJECTED로 그럴듯하게 나오면 끝. 그런데 첫 호출부터 막혔다.2. 첫 삽질: Claude 호출이 자꾸 실패한다 — 타임아웃이 문제였다콘텐츠를 등록하고 검증 상태를 조회했더니, 자꾸 FAILED로 떨어졌다. 처음엔 프롬프트나 파싱 로직을 의심했는데, 로그를 보니 원인은 훨씬 단순했다. Claude 응답이 오기도 전에 애플리케이션이 먼저 타임아웃을 내고 있..
[TIL-260717] readTimeout 하나 고치려다 ClaudeClient를 다시 설계하게 된 이야기
·
Backend/Architecture & Design
기능 개발을 마치면 우리 팀은 PR을 올리고 꼼꼼하게 코드 리뷰를 주고받는다.리뷰는 단순히 버그를 찾는 수준을 넘어, 더 좋은 구조와 유지보수하기 쉬운 설계 방향까지 함께 고민해 주는 문화가 자리 잡혀 있다. 잘한 부분은 왜 좋았는지 이야기해 주고, 개선할 부분은 어떤 점을 보완하면 더 좋은 구조가 될지 이유와 함께 제안해 준다.이번 글도 그런 리뷰를 통해 배우고 개선한 내용을 정리한 기록이다.처음에는 Claude API의 readTimeout 설정 하나만 수정하면 끝날 일이라고 생각했다.하지만 리뷰를 따라 코드를 하나씩 살펴보면서,HTTP 타임아웃과 애플리케이션 타임아웃이 서로 어떤 영향을 주는지 이해하게 되었고,재시도가 여러 계층에서 중복되고 있다는 구조적인 문제를 발견했으며,결국 ClaudeClie..
[TIL-260708] RAG를 안 쓰기로 했는데, 그래서 RAG가 뭔데?
·
AI
1. 배경이번에 팀 프로젝트를 하면서 두 번의 기술 설계 논의를 거쳤다. 하나는 "사용자가 입력한 콘텐츠가 개발 관련 콘텐츠인지 어떻게 판단할 것인가"였고, 다른 하나는 "사용자의 학습 이력을 바탕으로 개인화된 문제를 추천할 수 있을까"였다.두 논의 모두 결론은 같았다. "이번엔 RAG는 안 쓴다."재밌는 건, 정작 나는 RAG를 "안 쓰기로" 결정하는 과정에서 RAG가 뭔지 처음 제대로 이해하게 됐다는 거다. 그전까지는 "문서 검색해서 LLM한테 참고시키는 것" 정도로만 알고 있었고, 임베딩은 이번 프로젝트 전까지 잘 알지 못했던 용어였다.그래서 이 글은 "RAG 개념 정리"라기보다는, RAG를 쓰지 않기로 한 두 번의 논의를 따라가면서 거꾸로 배운 것들의 기록에 가깝다.2. 첫 번째 논의: 콘텐츠 적..
[일상] 부트캠프 수료 후기 & 앞으로의 계획
·
일상 || 잡담
부트캠프 수료!올해 1월 초부터 시작했던 부트캠프가 드디어 7/2, 어제 종료되었다. 시간이 참 빠른 것 같다. '벌써 수료라고? 6개월이 지났다고?' 싶으면서도 처음 팀 프로젝트 했던 기억을 떠올리면 되게 까마득하다.ㅋㅋㅋ 그동안 참 많은 걸 경험하고 배운 것 같다. 첫 프로젝트 때만 해도 깃 브랜치 전략도 모르고, 이슈랑 PR 생성하는 것도 모르고 그냥 어떻게 하다 보니 5일 프로젝트가 완성 됐는데, 그때만 해도 클로드는 써보지도 않았고 구글 안티그래비티 쓰면서 엄청 신기해했었다. '우와 AI가 자동으로 코드를 써줘!' 했었는데 지금 생각해 보면 정말 아무것도 몰랐구나 싶다. 이제는 나름 프로젝트 3번을 경험해 보면서 AI 사용도 좀 익숙해졌다. 물론 아직 단일 에이전트를 쓰고, 스킬이나 하네스 엔지..
[일상] 오랜만에 블로그
·
일상 || 잡담
들어가며오랜만에 블로그에 들어왔다.마지막 포스트 날짜를 보니 4/1이다. 무려 3개월 만에 컴백...!너무 오랜만에 글을 쓰니 어떻게 써야 할지, 어떻게 썼었는지 기억도 안 난다ㅋㅋㅋㅋ 내가 블로그를 했었다고?우선 근황 토크를 해보자면, 나는 지난 1월부터 한 백엔드 개발 부트캠프에 참여했고, 3번의 프로젝트 경험을 쌓고 어제(7/2) 수료를 했다. 이제 좀 여유가 생김 ㅎㅎ Why 떠남?블로그를 떠나게 된 것에 대한 변명 아닌 변명을 하자면,, 처음에는 '매일 매일 TIL 올려야지!' 하고 각오했으나, 점점 그게 힘들어졌다. 초반에 프론트엔드랑 자바 기초 배울 땐 괜찮았는데 스프링 들어가면서 수업 진도 따라가기도 벅찼고, TIL 작성을 위해 필기를 하면서 듣다 보니 강의를 놓치는 부분도 많이 생겼다 ㅠ..
[TIL-260331] Spring Boot 기초: Spring Data JPA
·
Backend/Spring
어제 상품을 판매하는 애플리케이션을 만들기로 하고, myShop이라는 새 프로젝트를 생성했다.Spring Boot Dev Tools, Spring Web, Thymeleaf, Lombok, Spring Data JPA, MySQL Driver, H2 Database 등의 Dependencies를 추가해 줬었고, 어제 Lombok에 대해서만 알아 보았다.오늘은 본격적으로 애플리케이션을 구성해 보았다.pom.xml 수정스프링 부트 버전을 2.7.1로 낮추어야 해서 pom.xml을 조금 수정해주었다. 4.0.0 org.springframework.boot spring-boot-starter-parent 2.7.1 com.exampl..
[TIL-260330] Spring Boot 기초: 개요, 실습, Lombok
·
Backend/Spring
Spring Boot란?복잡한 설정 없이 빠르게 실행 가능한 Spring 애플리케이션을 만들 수 있는 프레임워크이다. 기존 Spring의 문제점 Spring Boot의 해결 방식 XML 설정 파일이 많음자동 구성톰캣 등 WAS 설치 필요내장 톰캣 제공 (jar 실행)의존성 직접 추가 복잡Starter 의존성 제공실행까지 구조가 복잡main() 메서드 한 줄로 실행새로운 프로젝트 세팅에 오래 걸림Spring Initializr로 바로 시작 가능 Spring Boot의 특징XML 설정 없이 단순 자바 수준의 설정 방식 제공톰캣 같은 WAS 자체 내장내장 서버를 이용해 별도 설정 없이 실행 가능빌드 구성을 단순화하기 위한 Spring Boot Starter 의존성 제공 (필요한 기능만 골라 쓸 수 있음)JA..
[TIL-260326] DTO, VO, Entity, Domain 뭐가 다른걸까..???
·
Backend/Architecture & Design
오늘 JPA 개념 설명을 들으면서 Entity, DTO가 등장했고, 이전에 사용하던 VO와 Domain 개념과 섞이면서 헷갈리는 부분이 많았다.그래서 이번에 각 개념을 역할 중심으로 정리해보려 한다.0. 전체 흐름 먼저 이해하기일반적인 구조는 다음과 같다.Controller ↔ DTO ↔ Service ↔ Domain(Entity + VO) ↔ Repository ↔ DB 핵심은 다음과 같다.DTO: 외부(클라이언트)와 데이터를 주고받는 역할Domain(Entity + VO): 내부 비즈니스 로직 처리1. DTO (Data Transfer Object, 데이터 전송 객체)프레젠테이션 계층과 도메인(Entity) 계층 사이에서 데이터 전달 전용으로 사용하는 객체이다.즉 Controller ↔ Service..
[TIL-260325] 스프링 프레임워크 기초: Ajax Response, RESTful 컨트롤러, MyBatis
·
Backend/Spring
트랜잭션과 AOP, 파라미터 검증도 배웠지만 중요도가 낮다고 생각하여 포스팅하지 않기로 했다.Ajax Response우선 Ajax에 대해 간단히 리마인드 해보면, Ajax는 웹 페이지 전체를 새로고침하지 않고, 자바스크립트를 이용해 서버와 비동기적으로 데이터를 교환하여 화면의 일부분만 동적으로 업데이트하는 웹 개발 기술이다. 즉 사용자가 이벤트를 발생시키면, 페이지 전체를 다시 로드하는게 아니라 자바스크립트가 HttpReqest를 사용해 서버에 비동기 요청을 보내고, 서버가 요청을 처리하고 데이터를 응답해주면 그 데이터를 받아 화면 일부분만 변경하는 것이다.스프링에서 Ajax Reponse를 보내는 방법을 예를 통해서 알아보겠다. 회원가입 시 중복 이메일 체크를 하기 위해 Ajax Request를 전송한..