본문으로 건너뛰기
← Work

CASE STUDY / BACKEND · SYSTEMS

TAKO

느린 외부 원장(블록체인)과 DB의 거래 상태를 일관되게 유지하는 경매 백엔드

Period
2025.08 — 2025.09 (5주)
Team
5인 팀
Role
팀장 · Backend · DApp
Context
SSAFY 13기 특화 프로젝트
Award
반 3위 우수상
Stack
Spring Boot · Web3j · Solidity · MySQL · Redis · QueryDSL
Repository
GitHub

Context

객체 인식 AI로 카드 하자를 검증하고, 블록체인 에스크로로 대금을 보관하는 TCG 카드 경매 서비스입니다. 거래의 핵심 상태 일부가 DB가 아닌 외부 원장(Ethereum)에 기록됩니다.

Problem

NFT 발행이나 트랜잭션 전송은 네트워크 합의 때문에 확정까지 수 초에서 수십 초가 걸립니다. 이를 동기 방식으로 처리하면 사용자는 오래 기다리고, 요청 스레드가 묶여 서버 전체가 느려질 수 있었습니다.

Architecture

  • API 계층: 요청을 받으면 도메인 이벤트(NftMintEvent)를 발행하고 바로 응답합니다.
  • 비동기 리스너: 별도 스레드 풀의 리스너가 Web3j로 컨트랙트를 호출합니다.
  • 상태 동기화: 결과에 따라 DB 상태를 MINTING_SUCCESS/MINTING_FAILED로 갱신하고, 누락에 대비해 온체인 상태를 주기적으로 확인합니다.

My Contribution

  1. 팀장으로 기능 범위와 일정을 조율했습니다.
  2. 경매 에스크로 스마트 컨트랙트를 작성했습니다.
  3. Spring Security 기반 인증 API를 구현했습니다.
  4. Web3j로 블록체인-DB 정합성 검증과 낙찰 후속 처리 리스너를 구현했습니다.

Engineering Decisions

이벤트 기반 비동기 처리

컨트롤러가 블록체인 응답을 기다리지 않도록 ApplicationEventPublisher로 이벤트를 발행하고 @Async 리스너가 트랜잭션을 처리하게 했습니다. 요청 흐름과 외부 원장 처리가 분리되어 응답성과 결합도가 함께 개선됐습니다.

Troubleshooting

비동기 도입 뒤의 정합성 문제

응답은 빨라졌지만, 백그라운드에서 트랜잭션이 실패하면 사용자는 성공 응답을 받았는데 NFT는 발행되지 않는 상황이 생길 수 있었습니다.

  1. 리스너에서 성공·실패를 DB 상태로 즉시 기록해, 결과가 항상 상태로 남도록 했습니다.
  2. 이벤트 누락이나 타임아웃에 대비해 @Scheduled로 온체인 상태를 다시 확인하고 DB와 맞추는 보완 경로를 두었습니다.

Result

  • SSAFY 13기 특화 프로젝트 반 3위 우수상
  • 느린 외부 시스템을 호출하면서도 사용자 요청은 즉시 응답하는 구조를 구현

Retrospective

“느린 원장을 어떻게 빠르게 느끼게 할 것인가”가 핵심 질문이었습니다. 다만 Spring 인메모리 이벤트는 서버가 재시작되면 처리 중인 이벤트가 사라질 수 있습니다. 다음에는 Kafka 같은 외부 브로커로 메시지 영속성과 재시도 정책을 갖추고 싶습니다.

09 — RELATED MEDIA & WRITING