Skip to content

닉네임 변경/소셜 첫 로그인 동시성 레이스 컨디션 수정 - #253

Merged
unam98 merged 2 commits into
mainfrom
feature/nickname-race-fixes
Aug 23, 2026
Merged

닉네임 변경/소셜 첫 로그인 동시성 레이스 컨디션 수정#253
unam98 merged 2 commits into
mainfrom
feature/nickname-race-fixes

Conversation

@unam98

@unam98 unam98 commented Aug 23, 2026

Copy link
Copy Markdown
Collaborator

작업 배경

변경 사항

영역 내용
UserService.updateUserNickname existsByNickname 체크 후 더티 체킹으로만 변경하던 것을, saveAndFlush로 메서드 안에서 직접 flush해 DataIntegrityViolationExceptionDuplicateNicknameException(409)으로 변환
AuthService.signIn + SocialSignUpRegistrar(신규) 신규 유저 저장을 REQUIRES_NEW로 분리된 트랜잭션에서 실행. 실패(유니크 제약 위반)해도 그 트랜잭션만 롤백되고, signIn()의 트랜잭션에서 예외를 잡아 무시 → 두 요청 모두 로그인에 성공

두 레이스는 겉보기엔 같은 패턴이지만 해결 방식이 다르다: 닉네임 변경은 두 요청이 "서로 다른 유저의 서로 다른 의도"라 한쪽에 409를 주는 게 맞고, 소셜 로그인은 두 요청이 "같은 계정으로 로그인 성공"이라는 동일한 결과를 원하므로 실패를 조용히 흡수하고 둘 다 성공시키는 게 맞다. 후자는 Postgres가 트랜잭션 내 실패한 문장 이후 모든 명령을 거부하는 특성 때문에 단순 catch로는 안 되고, 저장을 별도 트랜잭션(REQUIRES_NEW)으로 격리해야만 가능했다 — 실제로 캐치 후 그대로 커밋을 시도했다가 UnexpectedRollbackException으로 재차 실패하는 것을 먼저 재현한 뒤 지금 구조로 수정했다.

영향 범위

  • 두 API 모두 동시 요청 시 500이 나던 경로를 정상 응답(409 또는 정상 로그인)으로 바꾼다. 정상 경로(레이스가 없는 경우)의 동작은 변경 없음.
  • 런타임 영향: AuthService에 트랜잭션 전파 방식이 다른 신규 저장 경로가 추가됨. 그 외 신규 컴포넌트/필드 없음.

검증 매트릭스

영향 범위 테스트 코드
동시에 같은 새 닉네임으로 변경 요청 시 한쪽만 성공(409)하고 데이터가 깨지지 않음 동시에_서로_다른_유저가_같은_닉네임으로_변경하면_한쪽만_성공한다
같은 소셜 계정으로 동시 첫 로그인 시 둘 다 성공하고 유저는 1건만 생성됨 동시에_같은_소셜계정으로_첫_로그인하면_둘_다_로그인에_성공한다

두 테스트 모두 수정 전 코드에 대해 먼저 실행해 실제 예외(DataIntegrityViolationException, 이후 UnexpectedRollbackException)가 그대로 새는 것을 확인한 뒤, 수정 후 통과함을 재검증했다.

Test Plan

  • 위 재현 테스트 2건 (수정 전 실패 확인 → 수정 후 통과 확인)
  • 전체 테스트 스위트 263건 통과 (회귀 없음)
  • 실제 배포 후 모니터링(Sentry/Slack)으로 해당 409/로그인 성공 케이스 관측

🤖 Generated with Claude Code

서로 다른 두 유저가 동시에 같은 새 닉네임으로 변경을 요청하면 중복 조회에서
둘 다 통과해 변경을 시도할 수 있다. 더티 체킹이라 트랜잭션 커밋 시점에야
DataIntegrityViolationException이 터져 그대로 500으로 샜음을 재현 테스트로
확인한 뒤, saveAndFlush로 메서드 안에서 직접 잡아 DuplicateNicknameException
(409)으로 변환했다.
같은 소셜 계정으로 첫 로그인 요청이 동시에 들어오면(더블탭, 타임아웃 재시도 등)
가입 여부 확인에서 둘 다 미가입으로 보고 각자 저장을 시도할 수 있다.
(email, provider) 유니크 제약으로 DB가 하나는 거부하는데, 이 예외가 그대로
새서 실제로는 가입에 성공한 요청까지 500으로 실패했음을 재현 테스트로 확인했다.

이 레이스는 스크랩 레이스와 달리 두 요청 모두 "같은 계정으로 로그인 성공"을
원하므로 409 대신 실패한 저장 시도만 무시하고 둘 다 로그인에 성공시켜야 한다.
Postgres는 트랜잭션 안에서 한 번 실패한 문장이 있으면 이후 모든 명령을 거부하므로,
저장을 REQUIRES_NEW로 분리된 트랜잭션(SocialSignUpRegistrar)에서 실행해
실패해도 로그인 트랜잭션의 후속 조회가 정상 동작하게 했다.
@coderabbitai

coderabbitai Bot commented Aug 23, 2026

Copy link
Copy Markdown

Warning

Review limit reached

@unam98, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 59 minutes

Limit details: You’ve used the included review currently available.

You've used all free OSS reviews for now. Wait for the free limit to reset to keep reviewing this public repository.

How can I continue?

Wait for the limit to reset, then comment @coderabbitai review or push new commits to the PR.

An organization admin can change what happens after included review limits in Billing.

How do review limits work?

CodeRabbit enforces per-developer PR review limits within each organization.

For paid Pro and Pro+ reviews, CodeRabbit uses a developer's included PR review attempts over the past 7 days to set the current hourly allowance. At typical activity levels, the full plan allowance applies. Higher sustained activity can lower the allowance until earlier attempts leave the 7-day window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: a8fda146-225f-4ece-bbdb-ebc79bbd3755

📥 Commits

Reviewing files that changed from the base of the PR and between 0a8a26e and 03d8a6c.

📒 Files selected for processing (6)
  • src/main/java/org/runnect/server/auth/service/AuthService.java
  • src/main/java/org/runnect/server/auth/service/SocialSignUpRegistrar.java
  • src/main/java/org/runnect/server/user/service/UserService.java
  • src/test/java/org/runnect/server/auth/service/AuthServiceSignInConcurrencyTest.java
  • src/test/java/org/runnect/server/auth/service/AuthServiceTest.java
  • src/test/java/org/runnect/server/user/service/UserNicknameConcurrencyTest.java

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@unam98
unam98 merged commit ff0a1ab into main Aug 23, 2026
2 checks passed
@unam98
unam98 deleted the feature/nickname-race-fixes branch August 23, 2026 12:54
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants