에이전트 이벤트 서버를 외부 도구 없이 직접 셀프호스팅한 이유
목차
자체 agent event server를 처음부터 새로 올린 작업이었다.
Python 백엔드 + 정적 HTML UI 조합으로, 기존 외부 도구에 의존하지 않고 에이전트 이벤트를 직접 수신·시각화하는 서버를 팀 내에서 셀프호스팅하기로 했다. 파일 목록을 보면 server.py, index.html, hook.mjs, start.sh, README.md, .gitignore — 전형적인 "최소 실행 가능한 독립 서비스" 구성이다.
왜 자체 구현을 선택했나
외부 모니터링 도구를 붙이는 게 제일 빠른 선택지였다. 근데 이번에는 그 옵션을 내려놓았다. 이유는 크게 세 가지였음.
- 이벤트 스키마가 비표준이었다. 우리 agent가 내뱉는 이벤트 포맷이 범용 도구가 기대하는 구조와 달랐고, 어댑터를 짜는 공수가 자체 서버 짜는 공수랑 크게 다르지 않았다.
- 외부 SaaS로 이벤트를 보내는 것에 부담이 있었다. 에이전트가 처리하는 컨텍스트 데이터가 내부망 바깥으로 나가는 건 별도 검토가 필요한 문제였다.
- 팀원들이 UI를 커스터마이즈하고 싶어 했다. 이벤트별로 강조 표시, 필터링, 타임라인 뷰 같은 걸 직접 조정할 수 있는 여지가 없으면 장기적으로 불편해진다.
| 선택지 | 빠른 시작 | 커스터마이즈 | 데이터 제어 | 유지보수 부담 |
|---|---|---|---|---|
| 외부 SaaS 붙이기 | ✅ | ❌ | ❌ | 낮음 |
| 오픈소스 도구 셀프호스팅 | 중간 | 중간 | ✅ | 중간 |
| 자체 구현 (이번) | 중간 | ✅ | ✅ | 높음 |
유지보수 부담이 올라가는 건 알면서 선택한 거다. 그 트레이드오프를 팀과 공유하고 "초기엔 단순하게, 필요하면 붙인다"는 방향으로 합의했음.
구성 파일별 역할
agents/
├── server.py # Python HTTP 서버, 이벤트 수신 엔드포인트
├── index.html # 정적 UI, 이벤트 스트림 시각화
├── hook.mjs # 에이전트 훅, 이벤트 발행 클라이언트
├── start.sh # 서버 기동 스크립트
├── README.md # 셋업 가이드
└── .gitignore # 로컬 런타임 파일 제외
server.py가 핵심이다. Python으로 간단한 HTTP 서버를 올려서 hook.mjs가 POST로 쏘는 이벤트를 받아 저장하고, index.html이 그걸 폴링하거나 SSE(Server-Sent Events)로 받아 렌더링하는 구조를 잡았다. 복잡한 프레임워크 없이 Python 표준 라이브러리 수준에서 돌아가도록 의도적으로 단순하게 유지했음.
hook.mjs는 에이전트 쪽 코드에서 이벤트가 발생할 때 server로 쏘는 훅이다. .mjs 확장자에서 알 수 있듯이 ES Module 방식으로 작성했고, 에이전트 런타임이 Node 기반이라는 맥락을 담고 있다. Python 서버와 JS 훅이 공존하는 구조인데, 이게 처음 보는 사람에게는 약간 낯설 수 있어서 README에 흐름도를 같이 넣었다.
start.sh는 팀원 온보딩을 위한 장치다. 서버 기동에 필요한 환경 세팅, 포트 확인, Python 버전 체크 같은 것들을 스크립트 한 줄로 처리하도록 묶었음. 로컬 개발 환경에서 "그냥 ./start.sh 치면 된다"는 경험을 주는 게 목적이었다. 팀장 입장에서 이런 작은 DX(Developer Experience) 포인트들이 나중에 온보딩 질문 수를 줄여준다는 걸 반복 경험으로 알고 있어서, 첫 커밋부터 넣는 편이다.
회고
신규 서비스를 처음 올릴 때 제일 중요하게 생각하는 게 "얼마나 단순하게 시작하느냐" 다. 이번 구성도 의도적으로 의존성을 최소화했다. 데이터베이스 없음, 인증 없음, 빌드 스텝 없음. server.py 실행하면 끝나는 구조. 나중에 필요하면 붙이면 되고, 지금 필요 없는 걸 미리 붙이면 유지보수 빚이 된다.
.gitignore를 첫 커밋에 같이 넣는 습관도 이유가 있다. __pycache__, 로컬 로그 파일, .env 같은 것들이 실수로 커밋되면 나중에 정리하는 게 생각보다 번거롭다. 코드리뷰할 때도 "왜 이 파일이 여기 있지?" 하는 노이즈가 생긴다. 처음부터 깔끔하게 가는 게 낫다.
README도 그냥 형식 채우기로 넣은 게 아니다. hook.mjs와 server.py가 Python-JS 혼재 구조라 흐름을 글로 한 번 정리해두는 게 팀원 진입 장벽을 낮춰준다. 내가 다 기억하고 있어도 내가 없는 날 팀원이 혼자 셋업할 수 있어야 한다.
다음은 이벤트 필터링 UI랑 이벤트 영속성 처리 쪽을 봐야 할 것 같다.
🛒 이 글과 어울리는 추천 상품
*위 링크는 쿠팡파트너스 활동의 일환이며, 일정액의 수수료를 제공받을 수 있습니다.
댓글 0
첫 댓글 달아줘.