[feat] 관리자 페이지에 당일 가입자 수, 방문자 수 조회 로직 추가#106
Conversation
Walkthrough관리자 페이지에 당일 가입자 수와 방문자 수를 집계하고 표시하는 기능이 추가되었습니다. 이를 위해 사용자 액션 로그를 Elasticsearch에 저장하는 로직, 관련 엔티티 및 저장소, 서비스 계층, 관리자 API 및 대시보드 템플릿이 도입·수정되었습니다. 일부 워크플로우 메시지와 null 체크도 개선되었습니다. Changes
Sequence Diagram(s)sequenceDiagram
participant Admin as 관리자
participant AdminController
participant AdminSystemService
participant UserActionLogService
participant AdminUserService
participant AdminWaybleZoneService
participant UserActionLogRepository
Admin->>AdminController: /admin/api/daily-stats 요청
AdminController->>AdminSystemService: getDailyStats()
AdminSystemService->>UserActionLogService: getTodayUserRegistrationCount()
AdminSystemService->>UserActionLogService: getTodayActiveUserCount()
AdminSystemService->>AdminUserService: getTotalUserCount()
AdminSystemService->>AdminWaybleZoneService: getTotalWaybleZoneCount()
AdminSystemService->>AdminController: DailyStatsDto 반환
AdminController->>Admin: 통계 JSON 반환
sequenceDiagram
participant User as 사용자
participant UserService
participant UserActionLogService
participant UserActionLogRepository
User->>UserService: 회원가입 요청
UserService->>UserActionLogService: logUserRegister()
UserActionLogService->>UserActionLogRepository: save(UserActionLog)
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~20 minutes Assessment against linked issues
Assessment against linked issues: Out-of-scope changes
Possibly related PRs
Suggested labels
Suggested reviewers
Poem
Note ⚡️ Unit Test Generation is now available in beta!Learn more here, or try it out under "Finishing Touches" below. ✨ Finishing Touches
🧪 Generate unit tests
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. 🪧 TipsChatThere are 3 ways to chat with CodeRabbit:
SupportNeed help? Create a ticket on our support page for assistance with any issues or questions. CodeRabbit Commands (Invoked using PR comments)
Other keywords and placeholders
CodeRabbit Configuration File (
|
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (6)
.github/workflows/cd-develop.yml (1)
190-193: 배포 알림 메시지에서 브랜치·커밋 정보를 포함하는 방안을 고려해 주세요
메시지를 간결하게 변경한 것은 이해됩니다만, 어떤 브랜치(또는 커밋)가 배포됐는지 알 수 없으면 후속 모니터링‧Rollback 시 맥락 파악이 어렵습니다.
${{ github.ref_name }}또는${{ github.sha }}등을 함께 포함해 배포 대상 식별성을 높이는 것을 권장합니다.- -d "{\"content\": \"✅ EC2 배포 성공!\"}" \ + -d "{\"content\": \"✅ EC2 배포 성공! (branch: ${{ github.ref_name }})\"}" \src/main/java/com/wayble/server/user/service/UserService.java (1)
31-38: 비동기 로깅 로직 검증 필요회원가입 후 로깅 로직이 추가되었지만, 몇 가지 개선사항이 있습니다:
- Line 37에서 null을 직접 전달하고 있습니다
- 비동기 로깅 실패 시 예외 처리가 명시되어 있지 않습니다
다음과 같이 개선할 수 있습니다:
// 회원가입 로그 저장 (비동기) userActionLogService.logUserRegister( savedUser.getId(), req.loginType().name(), - null + savedUser.getUserType() != null ? savedUser.getUserType().name() : null );src/main/java/com/wayble/server/logging/config/LoggingAsyncConfig.java (1)
10-26: 비동기 로깅 설정 검토ThreadPool 설정이 전반적으로 적절하지만, 몇 가지 개선사항이 있습니다:
- 로깅용 스레드 풀 크기(코어 2, 최대 4)가 적절합니다
- 큐 용량 100도 합리적입니다
- shutdown 대기 시간 30초도 적절합니다
로깅에 대한 추가 설명을 주석으로 추가하는 것을 고려해보세요:
@Bean("loggingTaskExecutor") public Executor loggingTaskExecutor() { + // 사용자 액션 로깅을 위한 비동기 실행자 ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();src/main/java/com/wayble/server/logging/entity/UserActionLog.java (1)
42-45: ActionType enum 위치 고려enum이 클래스 내부에 정의되어 있습니다. 다른 클래스에서도 사용할 가능성이 있다면 별도 파일로 분리하는 것을 고려해보세요.
만약 다른 서비스나 컨트롤러에서도 ActionType을 참조해야 한다면:
// 별도의 ActionType.java 파일로 분리 public enum ActionType { USER_REGISTER, USER_TOKEN_REFRESH }src/main/java/com/wayble/server/admin/service/AdminSystemService.java (1)
56-92: 일일 통계 메서드가 잘 구현되었지만 개선 여지가 있습니다.전반적인 구현은 적절하나 몇 가지 개선점이 있습니다:
- LocalDate.now() 중복 호출 (line 58, 85)
- 개별 서비스 호출 실패 시 전체가 실패하는 구조
다음과 같이 개선할 수 있습니다:
public DailyStatsDto getDailyStats() { + LocalDate today = LocalDate.now(); try { - LocalDate today = LocalDate.now(); // 일일 가입자 수 long dailyRegistrationCount = userActionLogService.getTodayUserRegistrationCount(); // ... 기존 로직 ... } catch (Exception e) { log.error("Failed to get daily stats", e); // 에러 발생시 기본값 반환 return DailyStatsDto.builder() - .date(LocalDate.now()) + .date(today) // ... 나머지 동일 ...추가로 각 서비스 호출을 try-catch로 개별 처리하여 일부 실패 시에도 다른 데이터는 표시할 수 있도록 개선하는 것을 고려해보세요.
src/main/java/com/wayble/server/logging/service/UserActionLogService.java (1)
54-85: 토큰 갱신 로깅의 중복 체크 로직이 우수합니다.하루 1회 제한과 중복 체크 로직이 매우 좋습니다. 다만 개선 여지가 있습니다.
시간 일관성을 위해
LocalDateTime.now()를 한 번만 호출하는 것을 고려해보세요:public CompletableFuture<Void> logTokenRefresh(Long userId, String userType) { try { + LocalDateTime now = LocalDateTime.now(); HttpServletRequest request = getCurrentRequest(); // 하루에 한 번만 로그 저장하도록 체크 - LocalDateTime startOfDay = LocalDateTime.now().toLocalDate().atStartOfDay(); + LocalDateTime startOfDay = now.toLocalDate().atStartOfDay(); LocalDateTime endOfDay = startOfDay.plusDays(1); // ... 중간 로직 ... if (existingCount == 0) { UserActionLog userActionLog = UserActionLog.builder() .userId(userId) .action(UserActionLog.ActionType.USER_TOKEN_REFRESH.name()) .userAgent(request != null ? request.getHeader("User-Agent") : null) - .timestamp(LocalDateTime.now()) + .timestamp(now) // ... 나머지 동일 ...
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (16)
.github/workflows/cd-develop.yml(1 hunks)src/main/java/com/wayble/server/ServerApplication.java(1 hunks)src/main/java/com/wayble/server/admin/controller/AdminController.java(4 hunks)src/main/java/com/wayble/server/admin/dto/DailyStatsDto.java(1 hunks)src/main/java/com/wayble/server/admin/service/AdminSystemService.java(3 hunks)src/main/java/com/wayble/server/admin/service/AdminUserService.java(3 hunks)src/main/java/com/wayble/server/auth/service/AuthService.java(4 hunks)src/main/java/com/wayble/server/auth/service/KakaoLoginService.java(3 hunks)src/main/java/com/wayble/server/logging/config/LoggingAsyncConfig.java(1 hunks)src/main/java/com/wayble/server/logging/entity/UserActionLog.java(1 hunks)src/main/java/com/wayble/server/logging/repository/UserActionLogRepository.java(1 hunks)src/main/java/com/wayble/server/logging/service/UserActionLogService.java(1 hunks)src/main/java/com/wayble/server/user/service/UserService.java(3 hunks)src/main/resources/templates/admin/dashboard.html(3 hunks)src/main/resources/templates/admin/user/user-detail.html(2 hunks)src/main/resources/templates/admin/user/users.html(2 hunks)
🧰 Additional context used
🧠 Learnings (1)
📚 Learning: java에서 같은 패키지 내의 클래스들은 import 구문 없이 서로를 참조할 수 있다. com.wayble.server.user.entity 패키지 내의 클래스들은 명시적인 im...
Learnt from: seung-in-Yoo
PR: Wayble-Project/wayble-spring#37
File: src/main/java/com/wayble/server/user/entity/User.java:61-62
Timestamp: 2025-07-13T15:08:59.318Z
Learning: Java에서 같은 패키지 내의 클래스들은 import 구문 없이 서로를 참조할 수 있다. com.wayble.server.user.entity 패키지 내의 클래스들은 명시적인 import 없이 사용 가능하다.
Applied to files:
src/main/java/com/wayble/server/logging/entity/UserActionLog.java
🧬 Code Graph Analysis (1)
src/main/java/com/wayble/server/admin/dto/DailyStatsDto.java (1)
src/main/java/com/wayble/server/common/response/CommonResponse.java (1)
Builder(8-42)
🔇 Additional comments (32)
src/main/java/com/wayble/server/ServerApplication.java (1)
18-18: LGTM! Elasticsearch 저장소 패키지 추가가 올바르게 설정되었습니다.새로운 로깅 기능을 위한
com.wayble.server.logging.repository패키지가@EnableElasticsearchRepositories에 올바르게 추가되었습니다. 이는UserActionLogRepository와 같은 새로운 Elasticsearch 저장소들이 Spring에서 정상적으로 스캔되고 등록될 수 있도록 합니다.src/main/resources/templates/admin/user/users.html (3)
102-103: LGTM! 사용자 타입에 대한 안전한 null 체크가 추가되었습니다.
user.userType이 null일 경우를 처리하여 NullPointerException을 방지하고 "미설정"이라는 적절한 대체 텍스트를 표시합니다. CSS 클래스 할당도 안전하게 처리됩니다.
106-107: LGTM! 로그인 타입에 대한 안전한 null 체크가 추가되었습니다.
user.loginType이 null일 경우를 처리하여 안전한 템플릿 렌더링을 보장합니다. 적절한 대체 텍스트와 CSS 클래스가 제공됩니다.
131-131: LGTM! 성별에 대한 안전한 null 체크가 추가되었습니다.
user.gender가 null일 경우를 처리하여 템플릿 렌더링 오류를 방지합니다. 백엔드의 null-safe 처리와 일관성을 유지합니다.src/main/resources/templates/admin/user/user-detail.html (3)
70-71: LGTM! 헤더 배지에서 사용자 타입에 대한 안전한 null 체크가 추가되었습니다.페이지 헤더의 사용자 타입 배지에서 null 값을 안전하게 처리하고 적절한 CSS 스타일링과 대체 텍스트를 제공합니다.
74-75: LGTM! 헤더 배지에서 로그인 타입에 대한 안전한 null 체크가 추가되었습니다.로그인 타입 배지에서 null 값을 안전하게 처리하여 템플릿 렌더링 오류를 방지합니다.
116-116: LGTM! 상세 정보 섹션에서 일관된 null 체크가 추가되었습니다.로그인 타입과 사용자 타입 필드에서 null 값을 안전하게 처리하여 users.html 템플릿과 일관된 방식으로 "미설정" 대체 텍스트를 표시합니다.
Also applies to: 120-120
src/main/java/com/wayble/server/admin/dto/DailyStatsDto.java (1)
7-15: LGTM! 일일 통계 DTO가 잘 설계되었습니다.
- Record 클래스 사용으로 불변성과 간결성을 보장합니다
@Builder어노테이션으로 인스턴스 생성이 편리합니다- 필드 타입들이 데이터 특성에 적합합니다 (날짜는
LocalDate, 개수는long)- 네이밍이 명확하고 일관성이 있습니다
관리자 대시보드의 일일 통계 표시 기능에 적합한 구조입니다.
src/main/java/com/wayble/server/admin/service/AdminUserService.java (3)
168-169: LGTM! 열거형 변환에 안전한 null 체크가 추가되었습니다.데이터베이스에서
LoginType과UserType값이 null일 경우를 처리하여IllegalArgumentException을 방지합니다. 이는 프론트엔드 템플릿의 null 체크와 일관성을 유지합니다.
184-185: LGTM! convertToDetailDto 메서드에서 일관된 null 체크가 적용되었습니다.다른 변환 메서드들과 동일한 방식으로 열거형 변환 전 null 체크를 수행하여 코드의 일관성을 유지합니다.
206-207: LGTM! convertToDetailDtoWithStats 메서드에서 일관된 null 체크가 적용되었습니다.세 개의 변환 메서드 모두에서 동일한 null-safe 열거형 변환 패턴을 사용하여 코드의 일관성과 안정성을 보장합니다.
src/main/java/com/wayble/server/user/service/UserService.java (2)
4-4: 의존성 추가 확인됨UserActionLogService 의존성이 올바르게 import되었습니다.
19-19: 의존성 주입 확인됨final 키워드와 함께 올바르게 의존성이 주입되었습니다.
src/main/java/com/wayble/server/auth/service/KakaoLoginService.java (3)
7-7: 의존성 추가 확인됨UserActionLogService import가 올바르게 추가되었습니다.
30-30: 의존성 주입 확인됨UserActionLogService가 올바르게 주입되었습니다.
72-85: 로깅 로직이 잘 구현되었습니다신규 사용자와 기존 사용자를 구분하여 로깅하는 로직이 올바르게 구현되었습니다. null 체크도 일관되게 적용되었습니다.
src/main/resources/templates/admin/dashboard.html (4)
61-61: 반응형 그리드 레이아웃 개선4개의 통계 카드를 수용하기 위한 그리드 레이아웃 변경이 적절합니다.
109-109: 아이콘 색상 변경 확인방문자 카드의 아이콘 색상이 purple로 변경되어 새로 추가되는 가입자 카드(orange)와 구분됩니다.
118-118: 동적 데이터 바인딩 확인Thymeleaf 표현식을 사용하여 실시간 방문자 수를 표시하도록 개선되었습니다.
125-144: 새로운 가입자 통계 카드 추가오늘 가입자 수를 표시하는 새로운 카드가 기존 디자인과 일관되게 추가되었습니다. 적절한 아이콘과 색상(orange)을 사용했습니다.
src/main/java/com/wayble/server/logging/entity/UserActionLog.java (2)
14-18: Lombok과 Elasticsearch 어노테이션 확인필요한 Lombok 어노테이션들이 올바르게 사용되었고, Elasticsearch Document 설정도 적절합니다.
21-40: 필드 매핑 검토Elasticsearch 필드 타입 매핑이 적절하게 설정되었습니다:
- ID는 자동 생성
- userId는 Long 타입으로 적절
- action, loginType, userType은 Keyword로 정확한 매칭 가능
- userAgent는 Text로 전체 텍스트 검색 가능
- timestamp는 Date 타입으로 시간 기반 쿼리 지원
src/main/java/com/wayble/server/auth/service/AuthService.java (3)
26-26: 의존성 주입 적절합니다.UserActionLogService 의존성이 올바르게 추가되었습니다.
47-51: 로그인 시 활성 유저 로깅이 적절합니다.비동기 처리와 하루 1회 제한으로 성능에 미치는 영향을 최소화했으며, 유저 타입 null 처리도 적절합니다.
85-89: 토큰 갱신 시 활성 유저 로깅이 적절합니다.토큰 재발급 시에도 활성 유저 로그를 저장하여 일일 방문자 통계에 반영하는 로직이 적절합니다.
src/main/java/com/wayble/server/admin/service/AdminSystemService.java (1)
22-24: 새로운 의존성 추가가 적절합니다.일일 통계 기능을 위한 필요한 서비스들이 올바르게 주입되었습니다.
src/main/java/com/wayble/server/admin/controller/AdminController.java (3)
3-3: 새로운 import 추가가 적절합니다.일일 통계 기능을 위한 필요한 클래스들이 올바르게 import되었습니다.
Also applies to: 8-8, 19-19
80-81: 대시보드에 일일 통계 데이터 추가가 적절합니다.기존 로직에 영향을 주지 않고 일일 통계 데이터가 올바르게 추가되었습니다.
Also applies to: 90-90
104-114: 일일 통계 API 엔드포인트가 잘 구현되었습니다.인증 체크, 에러 처리, 응답 형태 모두 적절하며 일관된 패턴을 따르고 있습니다.
src/main/java/com/wayble/server/logging/repository/UserActionLogRepository.java (1)
10-22: countDistinctUserIdByActionAndTimestampBetween 지원 여부 재확인 필요Spring Data Elasticsearch에서 파생된(Derived)
countDistinct…By방식이 자동으로 지원되는지 공식 문서나 통합 테스트로 반드시 확인하세요.
현재 인터페이스와 서비스 레이어에 선언·호출되어 있지만, Elasticsearch 쿼리로 올바르게 변환되지 않을 가능성이 있습니다.– 점검 대상
• src/main/java/com/wayble/server/logging/repository/UserActionLogRepository.java 라인 13
• src/main/java/com/wayble/server/logging/service/UserActionLogService.java – 호출부src/main/java/com/wayble/server/logging/service/UserActionLogService.java (2)
23-43: 사용자 등록 로깅 메서드가 잘 구현되었습니다.비동기 처리, 예외 처리, 로깅 모두 적절하며 성능에 미치는 영향을 최소화했습니다.
46-52: 일일 통계 조회 메서드들이 적절합니다.시간 범위 계산과 리포지토리 호출이 올바르게 구현되었습니다.
Also applies to: 87-93
| private HttpServletRequest getCurrentRequest() { | ||
| try { | ||
| ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); | ||
| return attributes != null ? attributes.getRequest() : null; | ||
| } catch (Exception e) { | ||
| log.debug("Failed to get current request", e); | ||
| return null; | ||
| } | ||
| } |
There was a problem hiding this comment.
💡 Verification agent
🧩 Analysis chain
HTTP 요청 컨텍스트 획득이 적절하지만 주의가 필요합니다.
비동기 컨텍스트에서 RequestContextHolder가 항상 작동하지 않을 수 있으므로 현재의 null 처리 방식이 적절합니다.
비동기 실행 시 RequestContextHolder 동작을 확인해보세요:
🌐 Web query:
Spring RequestContextHolder와 @Async 어노테이션 함께 사용할 때의 주의사항
💡 Result:
Spring에서 RequestContextHolder와 @Async 어노테이션을 함께 사용할 때는 ThreadLocal 기반 컨텍스트 관리의 한계를 반드시 주의해야 합니다. 비동기 메서드 실행 시 기존의 요청 스코프(RequestAttributes, 즉 request/session 등)가 새 스레드로 전달되지 않아, RequestContextHolder를 통한 값 조회가 실패하거나 null을 반환할 수 있습니다[1][5].
핵심 주의사항은 다음과 같습니다:
-
RequestContextHolder의 동작 방식
RequestContextHolder는 HttpServletRequest, Session 등의 요청/세션 기반 속성을 ThreadLocal에 저장하여 관리합니다[1][5]. 그러나@Async가 붙은 메서드는 별도의 스레드에서 실행되므로, 해당 ThreadLocal 컨텍스트가 새 스레드에는 기본적으로 전달되지 않습니다.
이로 인해, 비동기 메서드 내에서RequestContextHolder.getRequestAttributes()등을 호출하면 null이나 예상과 다른 값을 얻을 수 있습니다[5]. -
비동기 환경에서 Request/Session 정보 필요 시
비동기 메서드가 요청 스코프의 데이터를 필요로 한다면,- 필요한 값을 미리 추출해 파라미터로 넘겨야 합니다.
- 아니면, 컨텍스트 정보를 복사해 새 스레드에 전달하는 별도의 처리가 필요합니다[1][5].
-
컨텍스트 정보 복사/전달 패턴
실제로, 컨텍스트 복사를 위해 다음과 같은 패턴이 사용됩니다:- TaskExecutor 등 스레드 풀 구현체(CustomExecutor)를 오버라이딩해서,
호출 시점의 RequestAttributes를 별도로 캡처 및 전달(set/reset)하도록 래핑합니다[5]. 이런 식의 ContextAwareExecutor 구현이 널리 활용됩니다. - 또는 이미 필요한 데이터를 DTO/VO 형태로 변경 후, 메서드 파라미터로 직접 전달하는 것이 가장 안전합니다[1].
- TaskExecutor 등 스레드 풀 구현체(CustomExecutor)를 오버라이딩해서,
-
RequestContextHolder를 반드시 비동기에서 사용해야 한다면
- Spring DispatcherServlet의
setThreadContextInheritable(true)를 활용해 Context Inheritable ThreadLocal 기능을 켤 수 있지만, 이 방식은 여러 문제(메모리 누수, 컨텍스트 오염 등)로 인해 운영 환경에서 권장되지 않습니다[5]. - 일반적으로는 ThreadLocal 자체를 통한 요청 데이터 공유를 피하고, Service 계층에서는 반드시 필요한 데이터만 메서드 파라미터로 명시적으로 전달하는 것이 유지보수, 안정성 면에서 안전합니다[1][5].
- Spring DispatcherServlet의
-
@async 관련 일반 주의사항
- 반드시 public 메서드에만 지정, 내부 메서드(self-invocation) 또는 private 메서드는 적용되지 않음[2][3][6][7].
- 비동기 메서드의 예외 처리는 호출자에게 전파되지 않으니 별도의 AsyncUncaughtExceptionHandler 구현 필요[4].
- 별도의 ThreadPool 설정 없이 사용할 경우, 비효율적이거나 시스템 리소스 고갈 우려 있음. ThreadPoolTaskExecutor를 사용하여 풀 관리 권장[6][8][9][10].
종합적으로 볼 때,
RequestContextHolder를 그대로 비동기 메서드에서 사용하고 싶다면 직접 컨텍스트를 옮겨주는 코드(Executor 래핑 등)가 필요하며, 가장 권장되는 것은 "비동기에 필요한 데이터를 명시적으로 파라미터로 넘긴다" 입니다[1][5].
- "Spring RequestContextHolder를 이용해서 HttpServletRequest에 접근하는 메소드를 비동기로 처리하게 되면 thread가 달라져서 Spring RequestContextHolder를 이용하는데 실패하게 됩니다." [1]
- "RequestContextHolder는 ThreadLocal을 사용하여 attributes 들을 저장하고 있다. ... 비동기적으로 작업을 처리해야 할때가 있는데 이때 RequestContextHolder에 접근하게 되면 Thread가 달라 attributes가 원하는 값이 나오지 않게 된다." [5]
- "HttpServletRequest에서 필요한 값들을 모아서 VO(Value Object)로 만들고 파라미터로 service에게 넘긴다면 문제가 되지 않습니다." [1]
- "ThreadLocal 사용 시 내용 복사" [3]
- "ContextAwarePoolExecutor" 등 별도 구현을 통해 RequestAttributes 복사 후 세팅 [5]
Citations:
- 1: http://dveamer.github.io/backend/SpringAsyncSession.html
- 2: https://leechanwoo-kor.github.io/java/async/
- 3: https://cano721.tistory.com/208
- 4: https://dkswnkk.tistory.com/706
- 5: https://popawaw.tistory.com/331
- 6: https://velog.io/@wodyd202/Spring-boot-Async-%EC%82%AC%EC%9A%A9%EB%B2%95%EA%B3%BC-%EC%A3%BC%EC%9D%98%EC%82%AC%ED%95%AD
- 7: https://hoonsb.tistory.com/101
- 8: https://starryeye.tistory.com/177
- 9: https://stuffdrawers.tistory.com/8
- 10: https://cobinding.tistory.com/210
비동기(@async) 환경에서 RequestContextHolder 사용 주의
getCurrentRequest()로 HTTP 요청 컨텍스트를 획득하고 null 처리를 하는 것은 안전하지만, @async 메서드(별도 스레드)에서는 ThreadLocal 기반의 RequestAttributes가 전파되지 않아 항상 null이 반환될 수 있습니다.
필요 시 아래 중 하나를 적용해 주세요:
- 비동기 메서드에 필요한 요청 정보를 미리 추출하여 DTO/파라미터로 전달
- ContextAware Executor(또는 TaskExecutor 래퍼)를 구현해 호출 시점의 RequestAttributes를 캡처‧전달
- Spring의 inheritable ThreadLocal(
setThreadContextInheritable(true))은 메모리 누수 위험이 있으므로 권장되지 않음
추가 검토가 필요하다면, 비동기 로직에서 실제로 RequestContextHolder.getRequestAttributes()가 null인지 확인하고 적절한 전달 방식을 선택하세요.
🤖 Prompt for AI Agents
In src/main/java/com/wayble/server/logging/service/UserActionLogService.java
around lines 95 to 103, the getCurrentRequest() method uses RequestContextHolder
to obtain the HTTP request, which returns null in @Async methods due to
ThreadLocal context not being propagated. To fix this, avoid calling
getCurrentRequest() directly in asynchronous methods; instead, extract and pass
the necessary request information as method parameters or DTOs before the async
call, or implement a ContextAware Executor that captures and transfers the
RequestAttributes to the async thread. Do not rely on inheritable ThreadLocal
due to memory leak risks.
seung-in-Yoo
left a comment
There was a problem hiding this comment.
관리자 페이지 퀄리티가 ㅎㄷㄷ 하네요 ^.^ 수고하셨습니다~!!
✔️ 연관 이슈
📝 작업 내용
스크린샷 (선택)
Summary by CodeRabbit
신규 기능
버그 수정
스타일
기타