데이터가 몇 건 없을 때 빠른 화면은 어렵지 않습니다. 문제는 Client, Event와 이메일이 쌓인 뒤였습니다. 메뉴를 눌렀는데 빈 화면에서 기다리고, Gmail이나 DocuSign 확인이 끝날 때까지 다른 기록도 볼 수 없다면 기능이 많아져도 매일 쓰기 어렵습니다.
느린 이유는 서버 한 곳에 있지 않았다
처음에는 Railway 인스턴스나 Neon 데이터베이스가 느린 것처럼 보였습니다. 실제 흐름을 나눠보니 한 화면을 열면서 Event 전체, Client 후보, 브라우저 기록과 외부 서비스 상태를 동시에 기다리는 구조가 더 큰 원인이었습니다. 각각은 몇 초가 걸리지 않아도 직렬로 연결되면 사용자는 긴 빈 화면을 보게 됩니다.
속도 개선의 첫 원칙은 모든 작업을 빨리 만드는 것이 아니라, 지금 보여줄 수 있는 것을 먼저 보여주는 것이었습니다. 페이지 제목과 기본 목록을 먼저 렌더링하고, 다음 기록은 스크롤할 때 요청했습니다. 외부 API 상태는 화면을 막지 않고 별도 진행 표시로 바꿨습니다.
Event와 브라우저 기록을 조금씩 가져오기
Event History는 시간이 지날수록 계속 늘어나는 데이터입니다. 전체를 한 번에 가져오면 DB 조회뿐 아니라 서버의 직렬화, 네트워크 전송과 브라우저 렌더링 비용까지 함께 커집니다. 첫 페이지에는 최근 기록만 보여주고, 사용자가 아래로 내려갈 때 다음 묶음을 가져오도록 바꿨습니다.
브라우저에서 수집한 기록도 같은 원칙을 적용했습니다. 먼저 저장된 결과를 보여주고, 필요한 보완 정보는 뒤에서 채웠습니다. 사용자는 이미 있는 데이터를 검토할 수 있고, 시스템은 외부 페이지나 부가 정보를 준비하면서 화면을 계속 사용할 수 있습니다.
| 기존 방식 | 개선 방식 | 체감 변화 |
|---|---|---|
| Event 전체 로딩 | 최근 항목부터 페이지네이션 | 첫 화면 대기 감소 |
| 브라우저 자료 완성 후 표시 | 기존 결과 먼저 표시 | 검토를 바로 시작 |
| 외부 API 완료까지 대기 | 백그라운드 확인 | 다른 메뉴 사용 가능 |
| 상태가 보이지 않음 | Checking·완료·실패 표시 | 중복 클릭 감소 |
Gmail과 DocuSign은 화면보다 느릴 수 있다
외부 서비스는 SmartNexus가 통제할 수 없는 네트워크와 응답 시간을 가집니다. Gmail 동기화나 DocuSign 상태 확인을 버튼 클릭과 같은 요청 안에서 끝내려 하면, 응답이 늦을 때 사용자는 버튼이 작동하지 않은 것으로 생각합니다. 다시 누르면 같은 작업이 중복 실행될 위험도 있습니다.
확인 요청을 시작하면 먼저 Checking 상태를 보여주고 실제 처리는 백그라운드에서 진행하게 했습니다. 목록과 버튼에도 현재 상태를 표시했습니다. 완료되면 결과를 갱신하고 실패하면 다시 시도할 수 있는 단서를 남겼습니다. 기다림을 완전히 없앨 수 없을 때는 기다림의 이유와 상태를 숨기지 않는 것이 중요했습니다.
무한 스크롤에도 끝과 중복 방지가 필요하다
점진적 로딩은 단순히 아래에서 API를 다시 호출하는 기능이 아닙니다. 다음 페이지가 있는지, 요청 중인지, 같은 항목이 이미 화면에 있는지 구분해야 합니다. 검색 조건이 바뀌면 페이지 상태를 초기화하고, 늦게 도착한 이전 결과가 새 목록에 섞이지 않게 해야 합니다.
성능 개선은 체감 시간을 기준으로 측정했다
DB 쿼리가 빨라졌다는 숫자만으로는 충분하지 않았습니다. 메뉴를 누른 뒤 제목이 보이는 시간, 첫 기록이 나타나는 시간, 스크롤 중 멈춤과 버튼 상태가 바뀌는 시간을 따로 봤습니다. 사용자는 전체 작업 완료 시간보다 “지금 시스템이 반응하고 있다”는 첫 신호에 민감하기 때문입니다.
예를 들어 Gmail 확인이 8초 걸리더라도 기존 Client 목록을 1초 안에 볼 수 있고 상단에 Checking 표시가 나오면 다른 일을 계속할 수 있습니다. 반대로 모든 결과를 5초 만에 완성하더라도 그동안 빈 화면만 보이면 서비스가 멈춘 것으로 느낍니다. 그래서 skeleton, 상태 문구와 비활성 버튼도 성능 설계의 일부로 다뤘습니다.
백그라운드 작업에는 시간 제한과 재시도 간격도 필요했습니다. 외부 서비스가 응답하지 않을 때 무한히 기다리지 않고 실패 상태로 전환하며, 사용자가 다시 실행해도 이미 완료된 항목은 중복 처리하지 않도록 했습니다. 속도를 높이는 작업이 데이터 일관성을 해치지 않도록 결과 저장과 화면 갱신 순서도 함께 점검했습니다.
실무 체크리스트
- 첫 화면에 필요한 최소 데이터가 무엇인지 구분했는가?
- 계속 늘어나는 목록에 서버 측 페이지네이션이 있는가?
- 추가 로딩 중 같은 요청을 반복하지 않는가?
- 검색 조건 변경 시 이전 결과가 섞이지 않는가?
- Gmail·DocuSign 지연이 전체 화면을 막지 않는가?
- Checking, 성공과 실패 상태가 사용자에게 보이는가?
- 백그라운드 작업을 다시 실행해도 중복 처리되지 않는가?
- 모바일 네트워크에서도 첫 기록을 빠르게 볼 수 있는가?
FAQ
무한 스크롤이 페이지 번호보다 항상 좋은가요?
아닙니다. 최근 기록을 위에서부터 계속 살펴볼 때는 무한 스크롤이 편합니다. 하지만 특정 페이지나 자료로 다시 돌아가야 하는 보고서라면 페이지 번호 방식이 더 찾기 쉽습니다. SmartNexus는 화면의 용도에 맞춰 두 방식 중 알맞은 것을 사용합니다.
백그라운드 작업이 끝났는지는 어떻게 알 수 있나요?
Gmail이나 DocuSign 확인을 시작하면 화면에 ‘확인 중’이라고 표시합니다. 작업이 끝나면 최신 결과와 완료 상태를 보여주고, 실패하면 다시 시도할 수 있도록 안내합니다. 사용자는 화면이 멈춘 것인지 작업이 진행 중인지 바로 알 수 있습니다.
데이터베이스를 더 큰 요금제로 바꾸면 해결되지 않나요?
서버나 데이터베이스를 업그레이드하면 잠시 빨라질 수 있습니다. 그러나 화면을 열 때마다 모든 자료와 외부 서비스를 한꺼번에 불러오면 데이터가 늘면서 다시 느려집니다. 그래서 꼭 필요한 내용을 먼저 보여주고, 나머지는 뒤에서 불러오는 구조가 더 중요합니다.
백그라운드 작업은 중복 실행되어도 괜찮나요?
그대로 두면 안 됩니다. 사용자가 버튼을 여러 번 눌러도 이메일이 중복 발송되거나 같은 상태가 반복 변경되지 않도록 한 번만 처리해야 합니다. 이미 끝난 요청은 다시 실행하지 않고 완료된 결과만 보여주도록 막아야 합니다.
공식 자료
- Microsoft Learn: ASP.NET Core 성능 모범 사례
- Microsoft Learn: Background tasks with hosted services
- PostgreSQL 공식 문서: LIMIT과 OFFSET
관련 글
SmartNexus 서비스를 사용해 보고 싶으신가요?
SmartNexus 도입이나 사용을 원하시면 아래 댓글 또는 support@Active95.com으로 요청해 주세요.