NOWIL's Dev Blog
측정할 수 있어야 개선할 수 있다. Photo by Stephen Dawson on Unsplash.

Datadog 관측성 구축기 — LLM Observability와 구조화 로그

OpenAI 호출과 채용 공고 크롤링 기능을 운영하면서 예외 로그만으로는 느린 구간과 외부 API 실패 원인을 확인하기 어려웠습니다. 어떤 AI 기능이 느린가? 모델별 토큰 사용량과 비용은 어떻게 달라지는가? 실패가 OpenAI 장애인지 애플리케이션 계측 코드의 문제인지 어떻게 구분하는가? GraphQL 요청이 단일 엔드포인트로 보일...

JD 크롤러는 HTML 파서 하나가 아니라, 신뢰할 수 없는 입력을 제한하면서 여러 문서 구조를 단계적으로 해석하는 파이프라인이었다.

JD 크롤러 구현기 — 정적 HTML 파싱부터 SSRF 방어까지

Jobdori는 채용 공고(JD)를 바탕으로 지원 전략과 이력서를 만드는 서비스입니다. 이 서비스에 채용 공고를 등록할 때 긴 본문을 직접 복사하지 않고 URL만 입력할 수 있도록 크롤러를 구현했습니다. 처음에는 URL을 요청하고 Jsoup의 body.text()를 반환하면 끝날 것으로 생각했습니다. 하지만 사이트마다 HTML 구조가 달랐습니다. N...

비동기 데이터 흐름을 떠올리게 하는 네트워크 연결. Photo by Brett Sayles on Pexels.

AI 대화 후처리를 요청 트랜잭션에서 분리하기

AI 요청을 처리한 후에는 추가 분석이나 데이터 갱신처럼 사용자 응답과 바로 관계없는 작업이 이어질 수 있습니다. 이 작업을 모두 같은 요청에서 실행하면 외부 API를 기다리는 시간까지 응답이 늦어집니다. 이번 글에서는 요청 데이터가 저장된 후 코루틴으로 후처리를 실행하고 외부 API 호출과 저장 트랜잭션을 나누는 과정을 정리해보겠습니다. 아...

서로 다른 책임을 가진 구성 요소를 떠올리게 하는 블록. Photo by Duc Anh Nguyen on Pexels.

리워드 생성·수령·충전 책임을 분리한 과정

리워드 기능을 하나의 메서드에서 처리하면 처음에는 구현하기 쉽습니다. 하지만 생성, 상태 변경과 실제 반영이 한곳에 모이면 수정할 때마다 여러 책임을 함께 확인해야 합니다. 이번 글에서는 리워드의 생성·수령·충전 책임을 나누고 각 단계의 결과를 다음 유스케이스로 전달하는 구조를 정리해보겠습니다. 아래 도메인 이름, 상태, 처리 순서, 코드와 ...

Preview Image

[MCP] Blog Generator MCP 개발기 — AI로 기술 블로그를 자동 생성하는 MCP 서버 만들기

안녕하세요. 백엔드 개발자 정지원입니다. 요즘은 AI를 활용한 개발 자동화 도구를 만들고 있습니다. 이 글에서는 Blog Generator MCP를 설계한 과정부터 6번의 메이저 버전 업그레이드까지를 정리합니다. 이 글도 MCP의 도움을 받아 작성했습니다. 목차 블로그를 쓰고 싶지만 MCP란 무엇인가 전체 아키텍처 버전별 변화 ...

동시 요청의 최종 판정자는 데이터베이스다. Photo by panumas nikhomkhai on Pexels.

중복 리워드 처리를 막기 위해 상태 조건 UPDATE를 선택한 이유

상태를 확인한 후 엔티티를 저장하는 코드는 한 요청만 들어올 때에는 문제없이 동작합니다. 하지만 같은 자원을 여러 요청이 동시에 변경하면 두 요청이 모두 이전 상태를 읽을 수 있습니다. 이번 글에서는 이 문제를 재현하고 Spring Data JPA의 상태 조건 UPDATE로 중복 처리를 막는 과정을 정리해보겠습니다. 예제 코드 안내 아래...

Preview Image

TIL #1 [JAVA] Static 키워드에 대해

계기 스프링 프로젝트를 진행하면서 임시 데이터베이스 구현할때, MySQL과 같은 데이터베이스 서버를 사용하지 않고, 임시로 인메모리에 데이터를 저장하는 방식을 구현하였다. 이때, Database 클래스의 멤버 변수로 엔티티 리스트를 저장할 때 static 키워드를 사용하는 예제를 보고 static 키워드의 의미와 언제 사용해야 하는지 정리하였다. ...