-
Notifications
You must be signed in to change notification settings - Fork 3
08 10
📄 원본(노션): https://app.notion.com/p/3b819935b8ae805abd98cadf6e13c795 — 최종 동기화 2026-08-11
회의 날짜: 2026-08-10
- 동혁
- 주말에 여러개를 하려고 했는데 왔다갔다 하다보니 일은 많이 벌렸는데 완료한건 많이 없어서 평일 계속 진행 예정.
- Matching 정렬이 없는데 우선 오류 있는 로직, 정렬을 위한 구조
- SSE - 세션 이야기 필요해서 현 상황 분석 및 생각 해봄. (278 브랜치)
- 현성
- 배달 화면 부분 보완
- 배달할 때 주소 정보 추가
- 추적 화면 진입 시 드리미·부르미 지도 모두에 카카오 추천 도보 경로를 폴리라인으로 표시 - #276
- 카카오API 클라이언트 응답 추가
- 석희
- 비밀번호 암호화 기능
- 디비에 붙이기 위해서 공통 암호 제작 스크립트
- 레디스 스트림 + FCM 을 붙여서 알람 이중화
- 지난주에 heap 터지는거 관련해서 힙덤프를 까봄 → 정리해서 위키에 올리기
- 현서
- 드리미 화면 연동 안되어 있던 부분 완성
- 부하테스트
- 석희
- 매칭 기능 자동화하는 스크립트를 만듬
- k6 테스트 준비(- 현서님)
- 결제 관련 도메인 (+ 정산 받기 내일 만듬)
- 내일 할일
- 부르미 도메인 미흡한거 더 찾아보기
- 레디스 찾아보기
- 현성
- 드리미 수행 중에 웹브라우저 다시 로그인하면 드리미 페이지로 이동 안되는 문제
- 픽업 경로와 배송 경로 분리 및 배달 완료 예정 시간 추가
- 동혁
-
PR 머지 컨플릭 때문에 뭐 많이 못함…
-
DB, JVM 시간대 문제 수정
-
매칭 마이크로 배칭이랑 알고리즘 구현하려고 노력. 알고리즘은 다 됐는데 micro batching은 아직
-
머메이드
Loadingflowchart LR A["인메모리 상태<br/>OrderOfferGroup<br/>WaitingDreami<br/>MatchOffer"] B["ProblemAssembler<br/>엔진 상태를 입력으로 변환"] C["입력 객체<br/>MatchingOrderInput<br/>MatchingDreamiInput<br/>MatchingCandidate"] D["ProblemFactory<br/>Eligibility 적용<br/>후보 수 계산"] E["MatchingAssignmentProblem"] F["AssignmentPolicy<br/>Scoring 후 배정"] G["MatchingPlan<br/>오퍼 후보 목록"] H["PlanValidator<br/>capacity·중복·적격성 검증"] I["PlanApplier<br/>검증된 계획 반영"] J["Offering<br/>MatchOffer 생성<br/>PROPOSED / OPEN 전이<br/>Timeout 예약<br/>SSE 발송"] A --> B B --> C C --> D D --> E E --> F F --> G G --> H H --> I I --> J J -. "거절·만료·드리미 복귀" .-> A -
SSE 하트비트, 한 세션이 여러개의 emitter 가질 수 있게, polling을 통한 복구 메커니즘 매칭
-
- 현서
- 드리미 활동 내역 조회하는걸 부르미와 같은 쿼리 사용하게
- uploadsession 조건부 update wiki 작성
- 머지 충돌 해결
- 엣지 케이스 검증
- 내일까지 할 일
- K6 스크립트 만들기
- 드리미 본인인증 어드민 페이지
설계도
FE/Feat: SSE 장애 시 매칭 상태 polling 복구
SSE 연결 성공
→ polling 중단
→ 현재 상태 즉시 조회
SSE 연결 장애
→ 현재 상태 즉시 조회
→ 3초마다 polling
SSE 재연결
→ polling 중단
→ 현재 상태 다시 조회
Store에 추가:
syncCurrentMatching(): Promise<void>
응답이 null이면 기존 팝업도 제거해야 합니다.
테스트:
- 장애 시 polling 시작
- 재연결 시 polling 종료
- 재연결 직후 즉시 동기화
- 로그아웃 시 timer 제거
- 중복 polling 요청 방지
- null snapshot으로 오래된 팝업 제거
BE/Feat: 사용자당 SSE 연결을 최대 5개로 제한
현재 userId → connections 구조에서 바로 계산합니다.
sse.max-connections-per-user=5
정책:
- 5개까지 등록
- 6번째 연결은 거부
- 기존 연결은 종료하지 않음
- 연결 종료 후 빈 자리가 생기면 다시 연결 가능
- 제한 검사와 등록은 하나의
compute()에서 실행
6번째 연결은 204 No Content로 반환해 native EventSource의 자동 재연결을 중단시키는 방향이 안전합니다.
테스트:
- 5개까지 성공
- 6번째 거부
- 다른 사용자는 별도로 5개 허용
- 동시 요청에서도 정확히 5개
- 거부 연결은 active/opened 메트릭에서 제외
- 기존 connection 종료 후 신규 연결 성공
FE/Feat: SSE 연결 제한 상태 처리
Provider에서 일시 장애와 영구 종료를 구분합니다.
type SseStatus =
| 'connecting'
| 'connected'
| 'reconnecting'
| 'closed'
closed이면:
- 무한 재연결하지 않음
- 빠른 polling도 무한 실행하지 않음
- 다른 탭을 닫고 재시도하라는 안내
- 수동 재연결 제공
Docs: 단일 세션과 SSE의 다중 서버 확장 전략 정리
현재 구현은 단일 서버에서만 단일 세션을 보장합니다. 서버가 여러 대면 다음이 필요합니다.
-
ActiveSessionRegistry→ Spring Session Redis - emitter → 각 서버 로컬 유지
- 이벤트 전파 → Redis Pub/Sub
- 상태 복구 → 매칭 snapshot API
- 매칭 인메모리 상태의 외부화 또는 단일 소유권 보장
- 동일 사용자의 활성
HttpSession은 항상 하나 - 새 로그인 시 이전 디바이스 세션과 SSE가 응답 전에 종료
- 같은 브라우저의 여러 탭은 허용
- 한 탭당 EventSource 하나
- 로그아웃·세션 timeout 시 사용자 emitter 전체 종료
- heartbeat 실패는 해당 connection만 제거
- SSE 장애 중 매칭 상태 polling
- 재연결 직후 상태 즉시 동기화
- 사용자당 connection 최대 5개
- 세션 ID는 SSE registry·로그·메트릭에 노출되지 않음
Last-Event-ID는 넣을 수 있지만, 제대로 구현하려면 생각보다 변화가 큽니다. 단순히 이벤트에 ID를 붙이는 건 작지만, 재전송을 보장하려면 서버가 이벤트를 저장하고 연결·재생 사이의 순서까지 보장해야 합니다.
FE/Refactor: 탭당 SSE 연결을 하나로 통합
SseProvider
├── EventSource 하나
├── 연결 상태
└── eventName별 handler 목록
MatchingPopup, DeliveryTrackScreen, RealDeliveryTracking은 각각 연결을 생성하지 않고 handler만 Provider에 등록합니다.
이 작업 이후 의미가 명확해집니다.
- 세션 하나: 현재 로그인 브라우저
- connection 하나: 브라우저 탭 하나
- 사용자당 최대 5개: 동시에 열린 탭 최대 5개
테스트:
- 여러
useSse()호출에도 EventSource 하나 - handler별 이벤트 전달
- 화면 이탈 시 handler만 제거
- 로그아웃 시 EventSource 종료
- StrictMode에서도 최종 연결 하나
슬랙에 하시면 메시지 하나만!
- 오전에 마무리
- 자체 데모데이
- 전부 merge
- 의도했던 것중에서 뺄거 결정하기 (기능명세 확인)
- ex) 고객센터
- 데모 하면서 수정할거 다 잡기
- 할일 다 이슈화
Team 3 · 석희 · 현성 · 동혁 · 현서
Softeer Bootcamp 8th · WEB Team 3 · 이 위키는 팀 노션에서 동기화됩니다 📄
🏠 시작하기
🤝 협업
📋 기획안
🧠 기술 결정 기록 (ADR)
- 세션 vs 토큰
- 세션 및 다중 탭 처리 정책
- 실시간 배달 상태 전달에 SSE를 선택한 이유
- SSE 연결은 왜 1개였다가 5개가 되고, 다시 1개가 되었을까
- 드리미 GPS 끊김 감지 정책
- Redis 기반 로그인 대기열 도입기
- 카카오 API 응답 Redis 캐시 설계
- 활동 내역 조회를 커서 기반 페이지네이션으로 진행
- 알림 - WebPush 도입 이유와 SSE의 한계
- S3 Presigned URL 도입 결정
- 포인트, 머니 시스템 설계
🕸️매칭 시스템
- 매칭 시스템 설계
- Command와 Producer Consumer를 조합한 single writer 구조의 매칭 엔진
- 제안은 누구에게 해야 할까
- 쉼, 부름의 부르미‐드리미 매칭은 어떻게 동작할까
- 배정 정책에 Greedy 배정을 선택한 이유
- 매칭 시스템 구현
🧪 부하 테스트
- 매칭 부하테스트
- 매칭 부하테스트 보고서 (8.12)
- 매칭 부하테스트 보고서 (8.13)
- 매칭 부하테스트 보고서 (8.13 · 외부 API 트랜잭션)
- 매칭 부하테스트 보고서 (8.18 · 배포환경 720명)
🔧 트러블슈팅
- UploadSession - 옛 키 재사용 공격 방어 설계
- 8/6 · EC2 SSH 접속 불가
- 8/7 · 매칭 확정 후 Delivery가 생성되지 않는 고아 Order 문제
- 8/8 · 영속성 컨텍스트 detach로 dirty checking 미반영 문제 (@Modifying(clearAutomatically = true))
- 매칭 확정 후 Delivery가 생성되지 않는 고아 Order 문제
- 매칭이 성공하지 않았음에도 Orders 테이블에 PENDING으로 상태 변경하는 문제
- 부르미 확인 타임아웃 시 주문 DB·매칭 메모리 불일치
- 주변 콜 조회 시 반복되던 주문 조회 개선
- 드리미 오프라인 조회에 필요한 복합 인덱스 추가
- 매칭 단계 취소시 포인트 이중 환불 문제
- 로컬 DevStorage 사용시 로그인 상태에서도 401 UNAUTHORIZED 뜨던 문제
🗓️ 데일리 스크럼