Skip to content

Commit c6da512

Browse files
committed
perf: ConfigureAwait(false) 적용으로 데드락 방지
문제점: - async 메서드에서 ConfigureAwait 누락 - UI 스레드 블로킹으로 인한 데드락 위험 - 높은 부하 상황에서 성능 저하 수정사항: - TokenService 모든 async 호출에 ConfigureAwait(false) 적용 - AuthService 비즈니스 로직 메서드 최적화 - SqlServerUserRepository 데이터베이스 작업 최적화 - 컨텍스트 캡처 방지로 스레드 풀 효율성 향상
1 parent 46a1a25 commit c6da512

File tree

3 files changed

+28
-28
lines changed

3 files changed

+28
-28
lines changed

ProjectVG.Application/Services/Auth/AuthService.cs

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@ public async Task<AuthResult> GuestLoginAsync(string guestId)
3030
throw new ValidationException(ErrorCode.GUEST_ID_INVALID);
3131
}
3232

33-
var user = await _userService.TryGetByProviderAsync("guest", guestId);
33+
var user = await _userService.TryGetByProviderAsync("guest", guestId).ConfigureAwait(false);
3434

3535
if (user == null) {
3636
string uuid = GenerateGuestUuid(guestId);
@@ -41,23 +41,23 @@ public async Task<AuthResult> GuestLoginAsync(string guestId)
4141
Provider: "guest"
4242
);
4343

44-
user = await _userService.CreateUserAsync(createCommand);
44+
user = await _userService.CreateUserAsync(createCommand).ConfigureAwait(false);
4545
_logger.LogInformation("새 게스트 사용자 생성됨: UserId={UserId}, GuestId={GuestId}", user.Id, guestId);
4646
}
4747

48-
return await FinalizeLoginAsync(user, "guest");
48+
return await FinalizeLoginAsync(user, "guest").ConfigureAwait(false);
4949
}
5050

5151
private async Task<AuthResult> FinalizeLoginAsync(UserDto user, string provider)
5252
{
5353
// 초기 크레딧 지급
54-
var tokenGranted = await _tokenManagementService.GrantInitialCreditsAsync(user.Id);
54+
var tokenGranted = await _tokenManagementService.GrantInitialCreditsAsync(user.Id).ConfigureAwait(false);
5555
if (tokenGranted) {
5656
_logger.LogInformation("사용자 {UserId}에게 최초 크레딧 지급 완료", user.Id);
5757
}
5858

5959
// 최종 JWT 토큰 발급
60-
var tokens = await _tokenService.GenerateTokensAsync(user.Id);
60+
var tokens = await _tokenService.GenerateTokensAsync(user.Id).ConfigureAwait(false);
6161

6262
return new AuthResult {
6363
Tokens = tokens,
@@ -71,13 +71,13 @@ public async Task<AuthResult> RefreshAccessTokenAsync(string? refreshToken)
7171
throw new ValidationException(ErrorCode.TOKEN_MISSING);
7272
}
7373

74-
var tokens = await _tokenService.RefreshAccessTokenAsync(refreshToken);
74+
var tokens = await _tokenService.RefreshAccessTokenAsync(refreshToken).ConfigureAwait(false);
7575
if (tokens == null) {
7676
throw new ValidationException(ErrorCode.TOKEN_REFRESH_FAILED);
7777
}
7878

79-
var userId = await _tokenService.GetUserIdFromTokenAsync(refreshToken);
80-
var user = userId.HasValue ? await _userService.TryGetByIdAsync(userId.Value) : null;
79+
var userId = await _tokenService.GetUserIdFromTokenAsync(refreshToken).ConfigureAwait(false);
80+
var user = userId.HasValue ? await _userService.TryGetByIdAsync(userId.Value).ConfigureAwait(false) : null;
8181

8282
return new AuthResult {
8383
Tokens = tokens,
@@ -91,9 +91,9 @@ public async Task<bool> LogoutAsync(string? refreshToken)
9191
throw new ValidationException(ErrorCode.TOKEN_MISSING);
9292
}
9393

94-
var revoked = await _tokenService.RevokeRefreshTokenAsync(refreshToken);
94+
var revoked = await _tokenService.RevokeRefreshTokenAsync(refreshToken).ConfigureAwait(false);
9595
if (revoked) {
96-
var userId = await _tokenService.GetUserIdFromTokenAsync(refreshToken);
96+
var userId = await _tokenService.GetUserIdFromTokenAsync(refreshToken).ConfigureAwait(false);
9797
}
9898
return revoked;
9999
}

ProjectVG.Infrastructure/Auth/TokenService.cs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ public async Task<TokenResponse> GenerateTokensAsync(Guid userId)
2424
var accessTokenExpiresAt = DateTime.UtcNow.AddMinutes(15);
2525
var refreshTokenExpiresAt = DateTime.UtcNow.AddMinutes(1440);
2626

27-
var stored = await _refreshTokenStorage.StoreRefreshTokenAsync(refreshToken, userId, refreshTokenExpiresAt);
27+
var stored = await _refreshTokenStorage.StoreRefreshTokenAsync(refreshToken, userId, refreshTokenExpiresAt).ConfigureAwait(false);
2828
if (!stored)
2929
{
3030
_logger.LogError("Failed to store refresh token for user {UserId}", userId);
@@ -56,14 +56,14 @@ public async Task<TokenResponse> GenerateTokensAsync(Guid userId)
5656
return null;
5757
}
5858

59-
var isValid = await _refreshTokenStorage.IsRefreshTokenValidAsync(refreshToken);
59+
var isValid = await _refreshTokenStorage.IsRefreshTokenValidAsync(refreshToken).ConfigureAwait(false);
6060
if (!isValid)
6161
{
6262
_logger.LogWarning("Refresh token not found in storage");
6363
return null;
6464
}
6565

66-
var userId = await _refreshTokenStorage.GetUserIdFromRefreshTokenAsync(refreshToken);
66+
var userId = await _refreshTokenStorage.GetUserIdFromRefreshTokenAsync(refreshToken).ConfigureAwait(false);
6767
if (!userId.HasValue)
6868
{
6969
_logger.LogWarning("User ID not found for refresh token");
@@ -75,7 +75,7 @@ public async Task<TokenResponse> GenerateTokensAsync(Guid userId)
7575
var accessTokenExpiresAt = DateTime.UtcNow.AddMinutes(15);
7676

7777
// 기존 Refresh Token의 만료 시간 조회
78-
var refreshTokenExpiresAt = await _refreshTokenStorage.GetRefreshTokenExpiresAtAsync(refreshToken);
78+
var refreshTokenExpiresAt = await _refreshTokenStorage.GetRefreshTokenExpiresAtAsync(refreshToken).ConfigureAwait(false);
7979
if (!refreshTokenExpiresAt.HasValue)
8080
{
8181
_logger.LogWarning("Refresh token expiration time not found");
@@ -93,7 +93,7 @@ public async Task<TokenResponse> GenerateTokensAsync(Guid userId)
9393

9494
public async Task<bool> RevokeRefreshTokenAsync(string refreshToken)
9595
{
96-
return await _refreshTokenStorage.RemoveRefreshTokenAsync(refreshToken);
96+
return await _refreshTokenStorage.RemoveRefreshTokenAsync(refreshToken).ConfigureAwait(false);
9797
}
9898

9999
public async Task<bool> ValidateRefreshTokenAsync(string refreshToken)
@@ -110,7 +110,7 @@ public async Task<bool> ValidateRefreshTokenAsync(string refreshToken)
110110
return false;
111111
}
112112

113-
return await _refreshTokenStorage.IsRefreshTokenValidAsync(refreshToken);
113+
return await _refreshTokenStorage.IsRefreshTokenValidAsync(refreshToken).ConfigureAwait(false);
114114
}
115115

116116
public Task<bool> ValidateAccessTokenAsync(string accessToken)

ProjectVG.Infrastructure/Persistence/Repositories/User/SqlServerUserRepository.cs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -24,37 +24,37 @@ public async Task<IEnumerable<User>> GetAllAsync()
2424
return await _context.Users
2525
.Where(u => u.Status == AccountStatus.Active)
2626
.OrderBy(u => u.Username)
27-
.ToListAsync();
27+
.ToListAsync().ConfigureAwait(false);
2828
}
2929

3030
public async Task<User?> GetByIdAsync(Guid id)
3131
{
32-
return await _context.Users.FirstOrDefaultAsync(u => u.Id == id && u.Status != AccountStatus.Deleted);
32+
return await _context.Users.FirstOrDefaultAsync(u => u.Id == id && u.Status != AccountStatus.Deleted).ConfigureAwait(false);
3333
}
3434

3535
public async Task<User?> GetByUsernameAsync(string username)
3636
{
37-
return await _context.Users.FirstOrDefaultAsync(u => u.Username == username && u.Status != AccountStatus.Deleted);
37+
return await _context.Users.FirstOrDefaultAsync(u => u.Username == username && u.Status != AccountStatus.Deleted).ConfigureAwait(false);
3838
}
3939

4040
public async Task<User?> GetByEmailAsync(string email)
4141
{
42-
return await _context.Users.FirstOrDefaultAsync(u => u.Email == email && u.Status != AccountStatus.Deleted);
42+
return await _context.Users.FirstOrDefaultAsync(u => u.Email == email && u.Status != AccountStatus.Deleted).ConfigureAwait(false);
4343
}
4444

4545
public async Task<User?> GetByProviderIdAsync(string providerId)
4646
{
47-
return await _context.Users.FirstOrDefaultAsync(u => u.ProviderId == providerId && u.Status != AccountStatus.Deleted);
47+
return await _context.Users.FirstOrDefaultAsync(u => u.ProviderId == providerId && u.Status != AccountStatus.Deleted).ConfigureAwait(false);
4848
}
4949

5050
public async Task<User?> GetByProviderAsync(string provider, string providerId)
5151
{
52-
return await _context.Users.FirstOrDefaultAsync(u => u.Provider == provider && u.ProviderId == providerId && u.Status != AccountStatus.Deleted);
52+
return await _context.Users.FirstOrDefaultAsync(u => u.Provider == provider && u.ProviderId == providerId && u.Status != AccountStatus.Deleted).ConfigureAwait(false);
5353
}
5454

5555
public async Task<User?> GetByUIDAsync(string uid)
5656
{
57-
return await _context.Users.FirstOrDefaultAsync(u => u.UID == uid && u.Status != AccountStatus.Deleted);
57+
return await _context.Users.FirstOrDefaultAsync(u => u.UID == uid && u.Status != AccountStatus.Deleted).ConfigureAwait(false);
5858
}
5959

6060
public async Task<User> CreateAsync(User user)
@@ -65,14 +65,14 @@ public async Task<User> CreateAsync(User user)
6565
user.Status = AccountStatus.Active;
6666

6767
_context.Users.Add(user);
68-
await _context.SaveChangesAsync();
68+
await _context.SaveChangesAsync().ConfigureAwait(false);
6969

7070
return user;
7171
}
7272

7373
public async Task<User> UpdateAsync(User user)
7474
{
75-
var existingUser = await _context.Users.FirstOrDefaultAsync(u => u.Id == user.Id && u.Status != AccountStatus.Deleted);
75+
var existingUser = await _context.Users.FirstOrDefaultAsync(u => u.Id == user.Id && u.Status != AccountStatus.Deleted).ConfigureAwait(false);
7676
if (existingUser == null) {
7777
throw new NotFoundException(ErrorCode.USER_NOT_FOUND, "User", user.Id);
7878
}
@@ -85,22 +85,22 @@ public async Task<User> UpdateAsync(User user)
8585
existingUser.Status = user.Status;
8686
existingUser.Update();
8787

88-
await _context.SaveChangesAsync();
88+
await _context.SaveChangesAsync().ConfigureAwait(false);
8989

9090
return existingUser;
9191
}
9292

9393
public async Task DeleteAsync(Guid id)
9494
{
95-
var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == id && u.Status != AccountStatus.Deleted);
95+
var user = await _context.Users.FirstOrDefaultAsync(u => u.Id == id && u.Status != AccountStatus.Deleted).ConfigureAwait(false);
9696

9797
if (user == null) {
9898
throw new NotFoundException(ErrorCode.USER_NOT_FOUND, "User", id);
9999
}
100100

101101
user.Status = AccountStatus.Deleted;
102102
user.Update();
103-
await _context.SaveChangesAsync();
103+
await _context.SaveChangesAsync().ConfigureAwait(false);
104104
}
105105
}
106106
}

0 commit comments

Comments
 (0)