Skip to content

Conversation

Ji-soo708
Copy link
Member

@Ji-soo708 Ji-soo708 commented Jul 31, 2025

💡 작업 내용

  • 공고 키워드 자동완성 기능의 동시성 이슈 해결을 위한 INCR 연산 로직 추가
  • 관련 테스트 코드 추가
  • 기존 관련 인덱스 삭제

기존 문제
스크린샷 2025-07-31 오후 2 34 22

여러 스레드가 동시에 요청을 보내면 5개의 요청 모두가 처리되어 동시성 문제가 발생함을 확인함

스크린샷 2025-07-31 오후 2 54 16

DB 조회 대신 Redis의 INCR 연산을 사용하여 처리 후 테스트 진행

✅ 셀프 체크리스트

  • PR 제목을 형식에 맞게 작성했나요?
  • 브랜치 전략에 맞는 브랜치에 PR을 올리고 있나요?
  • 테스트는 잘 통과했나요?
  • 빌드에 성공했나요?
  • 본인을 assign 해주세요.
  • 해당 PR에 맞는 label을 붙여주세요.

🙋🏻‍ 확인해주세요

  • INCR을 선택한 이유에 대해서는 코멘트로 남기겠습니다~

🔗 Jira 티켓


https://yappsocks.atlassian.net/browse/YS-532

Summary by CodeRabbit

  • 신규 기능

    • 일일 사용량 제한을 Redis 기반으로 처리하는 기능이 추가되었습니다.
  • 버그 수정

    • 기존의 일일 사용량 제한 방식이 개선되어, 더 정확하게 제한이 적용됩니다.
  • 테스트

    • 동시성 환경에서 일일 사용량 제한이 올바르게 동작하는지 검증하는 테스트가 추가되었습니다.
    • 기존 테스트가 새로운 제한 방식에 맞게 수정되었습니다.
  • 기타

    • 불필요한 쿼리 및 인덱스가 제거되어 성능이 개선되었습니다.
    • 테스트 의존성(mockito-kotlin)이 추가되었습니다.

@Ji-soo708 Ji-soo708 self-assigned this Jul 31, 2025
@Ji-soo708 Ji-soo708 added ⚙️ CHORE config, workflow.yaml ♻️ REFACTORING 리팩토링 labels Jul 31, 2025
Copy link

coderabbitai bot commented Jul 31, 2025

Walkthrough

일일 사용 제한 검증 로직이 기존의 로그 카운팅 방식에서 Redis 기반의 UsageLimitGateway를 활용하는 방식으로 리팩터링되었습니다. 이에 따라 관련 인터페이스, 구현체, 테스트 코드, 마이그레이션 및 동시성 테스트가 추가·수정되었으며, 불필요해진 카운트 관련 메서드와 인덱스가 제거되었습니다.

Changes

Cohort / File(s) Change Summary
Use Case 및 테스트 리팩터링
application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt, application/src/test/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCaseTest.kt
일일 사용 제한 검증을 카운트 방식에서 UsageLimitGateway 활용 방식으로 변경. 생성자 및 테스트에 해당 Gateway 추가 및 관련 로직, 모킹, 검증 방식 수정.
Gateway/Repository 인터페이스 및 구현체 정리
domain/src/main/kotlin/com/dobby/gateway/UsageLimitGateway.kt, domain/src/main/kotlin/com/dobby/gateway/experiment/ExperimentPostKeywordsLogGateway.kt, infrastructure/src/main/kotlin/com/dobby/external/gateway/experiment/ExperimentPostKeywordsLogGatewayImpl.kt, infrastructure/src/main/kotlin/com/dobby/persistence/repository/ExperimentPostKeywordsLogRepository.kt
새로운 UsageLimitGateway 인터페이스 및 Redis 기반 구현체 추가. 기존 로그 카운트 관련 메서드 및 import 제거. 관련 리포지토리, 게이트웨이 인터페이스 및 구현체에서 카운트 메서드 삭제.
Redis 기반 사용 제한 구현
infrastructure/src/main/kotlin/com/dobby/external/gateway/cache/RedisUsageLimitGatewayImpl.kt
Redis를 이용한 일일 사용 제한 카운트 및 체크 기능 구현. 환경별 Prefix, 만료 시간 설정, 로그 출력 등 포함.
동시성 테스트 추가
infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt
여러 스레드에서 동시에 일일 사용 제한 체크가 올바르게 동작하는지 검증하는 동시성 테스트 클래스 추가.
빌드 및 마이그레이션
infrastructure/build.gradle.kts, infrastructure/src/main/resources/db/migration/V202507311527__remove_idx_experiment_keywords_log.sql
Mockito-Kotlin 테스트 의존성 추가, 불필요해진 인덱스 및 외래키 제약조건 재설정하는 마이그레이션 스크립트 추가.

Sequence Diagram(s)

sequenceDiagram
    participant User
    participant UseCase
    participant UsageLimitGateway (Redis)
    participant LogGateway

    User->>UseCase: 키워드 추출 요청
    UseCase->>UsageLimitGateway (Redis): incrementAndCheckLimit(memberId, dailyLimit)
    UsageLimitGateway (Redis)-->>UseCase: 사용 가능 여부(Boolean)
    alt 사용 가능
        UseCase->>LogGateway: 로그 저장
        UseCase-->>User: 키워드 추출 결과 반환
    else 사용 제한 초과
        UseCase-->>User: 일일 사용 제한 예외 발생
    end
Loading

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

Suggested labels

✅ TEST

Poem

🐇
Redis에 hop, hop, hop!
일일 제한, 더는 카운트에 stop.
동시성도 문제없지,
토끼처럼 빠르게 달리지!
로그는 가볍게,
테스트는 단단하게,
오늘도 코드는 깔끔하게!

Note

⚡️ Unit Test Generation is now available in beta!

Learn more here, or try it out under "Finishing Touches" below.

✨ Finishing Touches
  • 📝 Generate Docstrings
🧪 Generate unit tests
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch refact/YS-528

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
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Explain this complex logic.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai explain this code block.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and explain its main purpose.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Support

Need help? Create a ticket on our support page for assistance with any issues or questions.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR.
  • @coderabbitai generate sequence diagram to generate a sequence diagram of the changes in this PR.
  • @coderabbitai generate unit tests to generate unit tests for this PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@github-actions github-actions bot changed the title refactor: 실험 공고 키워드 자동완성 동시성 문제 해결을 위한 Redis INCR 연산 로직 추가 [YS-528] refactor: 실험 공고 키워드 자동완성 동시성 문제 해결을 위한 Redis INCR 연산 로직 추가 Jul 31, 2025
@Ji-soo708 Ji-soo708 changed the title [YS-528] refactor: 실험 공고 키워드 자동완성 동시성 문제 해결을 위한 Redis INCR 연산 로직 추가 [YS-532] refactor: 실험 공고 키워드 자동완성 동시성 문제 해결을 위한 Redis INCR 연산 로직 추가 Jul 31, 2025
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🧹 Nitpick comments (3)
domain/src/main/kotlin/com/dobby/gateway/UsageLimitGateway.kt (1)

3-5: 인터페이스 설계가 우수하나 문서화가 필요함

UsageLimitGateway 인터페이스는 단일 책임 원칙을 잘 따르고 있으며, incrementAndCheckLimit 메서드명이 원자적 연산을 수행한다는 의도를 명확히 전달합니다. 동시성 문제 해결에 적합한 설계입니다.

다만 메서드의 정확한 동작(반환값의 의미, 예외 상황 등)을 명확히 하기 위해 KDoc 추가를 권장합니다.

 interface UsageLimitGateway {
+    /**
+     * 회원의 일일 사용량을 증가시키고 제한을 확인합니다.
+     * 
+     * @param memberId 회원 ID
+     * @param dailyLimit 일일 사용 제한 수
+     * @return 제한 내라면 true, 제한 초과라면 false
+     */
     fun incrementAndCheckLimit(memberId: String, dailyLimit: Int): Boolean
 }
application/src/test/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCaseTest.kt (2)

57-57: 테스트 정확성 향상을 위한 구체적인 파라미터 사용 권장

any() 대신 실제 일일 제한값(예: 2)을 사용하면 올바른 제한값이 전달되는지 검증할 수 있어 테스트의 정확성이 향상됩니다.

-        every { usageLimitGateway.incrementAndCheckLimit(memberId, any()) } returns true
+        every { usageLimitGateway.incrementAndCheckLimit(memberId, 2) } returns true

81-81: 테스트 정확성 향상을 위한 구체적인 파라미터 사용 권장

마찬가지로 여기서도 구체적인 일일 제한값을 사용하는 것이 좋습니다.

-        every { usageLimitGateway.incrementAndCheckLimit(memberId, any()) } returns false
+        every { usageLimitGateway.incrementAndCheckLimit(memberId, 2) } returns false
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 376ab86 and 0765a2a.

📒 Files selected for processing (10)
  • application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt (2 hunks)
  • application/src/test/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCaseTest.kt (4 hunks)
  • domain/src/main/kotlin/com/dobby/gateway/UsageLimitGateway.kt (1 hunks)
  • domain/src/main/kotlin/com/dobby/gateway/experiment/ExperimentPostKeywordsLogGateway.kt (0 hunks)
  • infrastructure/build.gradle.kts (1 hunks)
  • infrastructure/src/main/kotlin/com/dobby/external/gateway/cache/RedisUsageLimitGatewayImpl.kt (1 hunks)
  • infrastructure/src/main/kotlin/com/dobby/external/gateway/experiment/ExperimentPostKeywordsLogGatewayImpl.kt (0 hunks)
  • infrastructure/src/main/kotlin/com/dobby/persistence/repository/ExperimentPostKeywordsLogRepository.kt (1 hunks)
  • infrastructure/src/main/resources/db/migration/V202507311527__remove_idx_experiment_keywords_log.sql (1 hunks)
  • infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt (1 hunks)
💤 Files with no reviewable changes (2)
  • domain/src/main/kotlin/com/dobby/gateway/experiment/ExperimentPostKeywordsLogGateway.kt
  • infrastructure/src/main/kotlin/com/dobby/external/gateway/experiment/ExperimentPostKeywordsLogGatewayImpl.kt
🧰 Additional context used
🧠 Learnings (3)
📓 Common learnings
Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#154
File: application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt:33-46
Timestamp: 2025-07-27T12:26:47.814Z
Learning: Gradmeet-BE 프로젝트에서 하루 최대 2회 사용 제한이 있는 기능의 경우, unique constraint나 낙관적 락 대신 DB 조회 기반 검증 방식을 선호한다. 분산 락은 나중에 최적화가 필요할 때 고려한다.
Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#140
File: domain/src/main/kotlin/com/dobby/gateway/auth/GoogleAuthGateway.kt:7-7
Timestamp: 2025-06-04T09:02:40.657Z
Learning: Ji-soo708의 팀은 로컬 ktlint 기준과 GitHub ktlint 체크 기준이 다를 때, 기존 코드베이스와의 일관성을 위해 로컬 기준을 우선시한다.
Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#154
File: infrastructure/src/main/kotlin/com/dobby/mapper/ExperimentPostKeywordsLogMapper.kt:15-22
Timestamp: 2025-07-27T12:37:15.372Z
Learning: Ji-soo708의 팀에서는 JSON 역직렬화 시 예외를 catch하여 래핑하기보다는, 예외를 자연스럽게 상위로 전파시켜 원본 컨텍스트를 보존하고 후속 조치를 용이하게 하는 것을 선호한다.
infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt (2)

Learnt from: Ji-soo708
PR: #150
File: infrastructure/src/main/kotlin/com/dobby/external/prompt/ExperimentPostKeywordMapper.kt:52-58
Timestamp: 2025-07-17T08:06:16.021Z
Learning: AI가 텍스트에서 키워드를 추출하는 과정에서 enum 변환 실패(IllegalArgumentException)는 정상적인 상황에 가깝다. 따라서 ExperimentPostKeywordMapper에서 TimeSlot, MatchType 등의 enum 변환 실패 시 로깅을 추가하지 않는 것이 적절하다.

Learnt from: chock-cho
PR: #93
File: src/main/kotlin/com/dobby/backend/infrastructure/coroutine/TransactionCoroutineExecutor.kt:15-24
Timestamp: 2025-02-12T04:30:30.826Z
Learning: In Spring transactions with Kotlin coroutines, using runBlocking within transactionTemplate.execute ensures that the transaction context is active during the execution of suspend functions. While this approach blocks the thread, it guarantees transaction safety by preventing async operations from executing outside the transaction boundary.

application/src/test/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCaseTest.kt (1)

Learnt from: Ji-soo708
PR: #150
File: infrastructure/src/main/kotlin/com/dobby/external/prompt/ExperimentPostKeywordMapper.kt:52-58
Timestamp: 2025-07-17T08:06:16.021Z
Learning: AI가 텍스트에서 키워드를 추출하는 과정에서 enum 변환 실패(IllegalArgumentException)는 정상적인 상황에 가깝다. 따라서 ExperimentPostKeywordMapper에서 TimeSlot, MatchType 등의 enum 변환 실패 시 로깅을 추가하지 않는 것이 적절하다.

🪛 detekt (1.23.8)
infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt

[warning] 149-149: The caught exception is swallowed. The original exception could be lost.

(detekt.exceptions.SwallowedException)

⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
  • GitHub Check: build
🔇 Additional comments (13)
infrastructure/build.gradle.kts (1)

70-70: 새로운 테스트 의존성 추가가 적절함

mockito-kotlin 의존성 추가는 새로운 UsageLimitGateway 인터페이스를 모킹하기 위한 테스트 요구사항을 지원합니다. 버전 4.1.0은 안정적이며 기존 테스트 인프라와 잘 어울립니다.

infrastructure/src/main/resources/db/migration/V202507311527__remove_idx_experiment_keywords_log.sql (1)

1-6: 외래키 제약조건 삭제·재생성은 적절합니다

InnoDB에서는 외래키 제약조건이 참조 컬럼(member_id)에 대한 인덱스를 필요로 하기 때문에, 복합 인덱스(idx_experiment_keywords_log)를 제거하려면

  1. 기존 외래키를 삭제하고
  2. 복합 인덱스를 DROP
  3. 외래키를 재생성하여 단일 컬럼(member_id) 인덱스를 자동 생성

하는 순서가 필수적입니다. 해당 마이그레이션은 위 절차에 맞게 올바르게 작성되었습니다.

infrastructure/src/main/kotlin/com/dobby/persistence/repository/ExperimentPostKeywordsLogRepository.kt (1)

6-6: 리포지토리 단순화가 적절함

countByMemberIdAndCreatedAtBetween 메서드 제거는 새로운 Redis 기반 사용량 제한 아키텍처와 일치합니다. 리포지토리가 기본 CRUD 연산에만 집중하도록 단순화된 것이 적절합니다.

application/src/test/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCaseTest.kt (1)

26-26: 새로운 게이트웨이 모킹 추가가 적절함

UsageLimitGateway 모킹 추가는 아키텍처 변경사항을 잘 반영하고 있습니다.

application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt (2)

5-5: 새로운 의존성 추가가 적절합니다.

UsageLimitGateway 의존성 추가가 리팩터링 목표와 일치하며, 의존성 주입 패턴을 올바르게 따르고 있습니다.

Also applies to: 17-17


50-51: 동시성 문제 해결을 위한 핵심 로직 개선이 우수합니다.

기존의 데이터베이스 카운팅 방식에서 Redis의 원자적 연산을 활용한 방식으로 변경하여 동시성 문제를 효과적으로 해결했습니다. API 호환성을 유지하면서 성능과 정확성을 모두 개선한 좋은 리팩터링입니다.

infrastructure/src/main/kotlin/com/dobby/external/gateway/cache/RedisUsageLimitGatewayImpl.kt (4)

13-19: 클래스 구조와 의존성 설정이 적절합니다.

Spring DI 어노테이션과 Redis 템플릿, 환경 프로파일을 활용한 구조가 멀티 환경 배포에 적합하게 설계되었습니다.


21-33: Redis INCR 연산을 활용한 동시성 안전한 구현입니다.

원자적 INCR 연산과 첫 번째 사용 시에만 만료 시간을 설정하는 최적화된 로직이 우수합니다. 동시성 문제를 효과적으로 해결하면서 성능도 고려한 구현입니다.


35-38: 캐시 키 구조가 잘 설계되었습니다.

프로파일별 분리와 날짜 기반 파티셔닝으로 환경 간 충돌 방지와 일일 리셋이 올바르게 구현되었습니다.


26-26: 시간대 일관성 확인을 권장합니다.

LocalDateTime.now()LocalDate.now()가 동일한 시간대를 사용하는지 확인해주세요. 배포 환경에서 시간대 설정이 일관되지 않으면 예상치 못한 만료 시간 계산이 발생할 수 있습니다.

infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt (3)

35-43: 동시성 테스트 설정이 체계적으로 구성되었습니다.

모든 필요한 의존성의 모킹과 실제 사용 시나리오를 반영한 테스트 데이터 설정이 우수합니다. 새로운 UsageLimitGateway의 동작을 올바르게 시뮬레이션하고 있습니다.

Also applies to: 59-112


114-136: 동시성 테스트 로직이 정확하게 구현되었습니다.

스레드 풀을 활용한 동시 요청 시뮬레이션과 원자적 카운터 동작 모킹이 실제 Redis 동작을 잘 반영하고 있습니다. 일일 한도 검증도 정확합니다.


149-153: 예외 처리가 테스트 목적에 적합합니다.

정적 분석 도구가 예외 삼키기를 경고했지만, 이 테스트에서는 예상되는 일일 한도 초과 예외를 의도적으로 카운팅하는 것이므로 올바른 구현입니다. 테스트의 목적상 예외를 다시 던지거나 로깅할 필요가 없습니다.

Comment on lines +21 to +33
override fun incrementAndCheckLimit(memberId: String, dailyLimit: Int): Boolean {
val key = getCacheKey(memberId)
val count = redisTemplate.opsForValue().increment(key, 1) ?: 1L

if (count == 1L) {
val expireSeconds = Duration.between(LocalDateTime.now(), LocalDate.now().plusDays(1).atStartOfDay()).seconds
redisTemplate.expire(key, expireSeconds, TimeUnit.SECONDS)
}

logger.debug("Usage count for key=$key is $count")

return count <= dailyLimit
}
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

동시성 문제 해결을 위해 비관적/낙관적 락과 분산 락을 고려할 수 있었으나, Redis의 INCR 연산을 선택한 이유는 다음과 같습니다.

  1. 비관적 락과 낙관적 락은 주로 UPDATE 작업에서 발생하는 동시성 이슈에 적합합니다.
  2. 분산 락은 단순히 사용자 사용 횟수를 제어하는 데에는 과도한 비용과 복잡성을 가져온다고 생각합니다.

INCR 연산은 Redis 내부에서 단일 명령으로 처리되므로 여러 요청이 동시에 실행되어도 정확한 카운트가 보장되어 race condition을 방지할 수 있습니다. 그래서 별도의 락 없이도 안전하게 사용 횟수를 제한할 수 있어 효율적입니다.

지금처럼 단순한 로직에 최소 비용으로 동시성 문제를 해결하기 위해, Redis의 INCR 연산을 통한 원자적 처리가 가장 적합하다고 판단했습니다!

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redis의 INCR 연산은 해당 작업을 통해 처음 공부해봤는데요, 지수님 덕분에 좋은 지식을 많이 얻어가네요!

@@ -0,0 +1,6 @@
ALTER TABLE experiment_post_keywords_log DROP FOREIGN KEY fk_experiment_post_keywords_log_member;

DROP INDEX idx_experiment_keywords_log ON experiment_post_keywords_log;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

기존 COUNT 쿼리를 사용하지 않게 되어, 매번 추가되는 행에 대해 인덱스를 생성하는 것이 불필요한 오버헤드로 작용한다고 판단하여 해당 인덱스를 삭제했습니다~

Copy link
Member Author

@Ji-soo708 Ji-soo708 Jul 31, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

해당 테스트 코드는 모킹을 통해 동시성 이슈 해결 여부를 확인하는 테스트입니다. 실제 Redis와 연결해 테스트하는 것이 더 정확하지만, 테스트 시간이 길고 무거워서 로컬에서만 통합 테스트를 진행했습니다. 그래서 실제 통합 테스트 코드는 삭제하고 모킹 기반 테스트 코드만 유지했습니다. 🥲

실제 통합 테스트 진행 내용은 블로그에 참고용으로 올렸습니다!

@Ji-soo708 Ji-soo708 requested a review from chock-cho July 31, 2025 06:47
@github-actions github-actions bot changed the title [YS-532] refactor: 실험 공고 키워드 자동완성 동시성 문제 해결을 위한 Redis INCR 연산 로직 추가 [YS-528] [YS-532] refactor: 실험 공고 키워드 자동완성 동시성 문제 해결을 위한 Redis INCR 연산 로직 추가 Aug 2, 2025
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FE에서 자동완성 기능 개발을 완료할 때까지 사용 횟수 제한을 풀어달라고 요청을 해서 임시로 관련 기능/테스트 코드는 주석처리했습니다!

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt (2)

25-32: 불필요한 @SpringBootTest 어노테이션 제거 고려

모킹 기반 단위 테스트에서 @SpringBootTest는 불필요하며 테스트 실행 속도를 느리게 만들 수 있습니다. @ExtendWith(MockitoExtension::class)만으로 충분합니다.

 @ExtendWith(MockitoExtension::class)
-@SpringBootTest
-@ActiveProfiles("test")
 class ExtractExperimentPostKeywordsConcurrencyTest {

84-89: 사용되지 않는 usageCount 변수 제거

usageCount 변수가 증가하기만 하고 실제로 사용되지 않습니다. 불필요한 코드는 제거하는 것이 좋습니다.

-        val usageCount = AtomicInteger(0)
-
         whenever(experimentPostKeywordsGateway.save(any())).thenAnswer {
-            usageCount.incrementAndGet()
             null
         }
📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 0765a2a and 589dfd8.

📒 Files selected for processing (3)
  • application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt (2 hunks)
  • application/src/test/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCaseTest.kt (4 hunks)
  • infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt (1 hunks)
🚧 Files skipped from review as they are similar to previous changes (2)
  • application/src/test/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCaseTest.kt
  • application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt
🧰 Additional context used
🧠 Learnings (5)
📓 Common learnings
Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#154
File: application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt:33-46
Timestamp: 2025-07-27T12:26:47.814Z
Learning: Gradmeet-BE 프로젝트에서 하루 최대 2회 사용 제한이 있는 기능의 경우, unique constraint나 낙관적 락 대신 DB 조회 기반 검증 방식을 선호한다. 분산 락은 나중에 최적화가 필요할 때 고려한다.
Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#140
File: domain/src/main/kotlin/com/dobby/gateway/auth/GoogleAuthGateway.kt:7-7
Timestamp: 2025-06-04T09:02:40.657Z
Learning: Ji-soo708의 팀은 로컬 ktlint 기준과 GitHub ktlint 체크 기준이 다를 때, 기존 코드베이스와의 일관성을 위해 로컬 기준을 우선시한다.
Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#154
File: infrastructure/src/main/kotlin/com/dobby/mapper/ExperimentPostKeywordsLogMapper.kt:15-22
Timestamp: 2025-07-27T12:37:15.372Z
Learning: Ji-soo708의 팀에서는 JSON 역직렬화 시 예외를 catch하여 래핑하기보다는, 예외를 자연스럽게 상위로 전파시켜 원본 컨텍스트를 보존하고 후속 조치를 용이하게 하는 것을 선호한다.
📚 Learning: ai가 텍스트에서 키워드를 추출하는 과정에서 enum 변환 실패(illegalargumentexception)는 정상적인 상황에 가깝다. 따라서 experimentpostkeywo...
Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#150
File: infrastructure/src/main/kotlin/com/dobby/external/prompt/ExperimentPostKeywordMapper.kt:52-58
Timestamp: 2025-07-17T08:06:16.021Z
Learning: AI가 텍스트에서 키워드를 추출하는 과정에서 enum 변환 실패(IllegalArgumentException)는 정상적인 상황에 가깝다. 따라서 ExperimentPostKeywordMapper에서 TimeSlot, MatchType 등의 enum 변환 실패 시 로깅을 추가하지 않는 것이 적절하다.

Applied to files:

  • infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt
📚 Learning: in the gradmeet-be project, redis lock operations should use lua scripts for atomic operations to en...
Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#106
File: src/main/kotlin/com/dobby/backend/infrastructure/lock/RedisLockManager.kt:23-32
Timestamp: 2025-02-17T06:19:55.617Z
Learning: In the Gradmeet-BE project, Redis lock operations should use Lua scripts for atomic operations to ensure thread safety in multi-threaded environments, particularly in the unlock operation where check-and-delete needs to be atomic.

Applied to files:

  • infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt
📚 Learning: gradmeet-be 프로젝트에서 하루 최대 2회 사용 제한이 있는 기능의 경우, unique constraint나 낙관적 락 대신 db 조회 기반 검증 방식을 선호한다. 분산 락...
Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#154
File: application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt:33-46
Timestamp: 2025-07-27T12:26:47.814Z
Learning: Gradmeet-BE 프로젝트에서 하루 최대 2회 사용 제한이 있는 기능의 경우, unique constraint나 낙관적 락 대신 DB 조회 기반 검증 방식을 선호한다. 분산 락은 나중에 최적화가 필요할 때 고려한다.

Applied to files:

  • infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt
📚 Learning: in spring transactions with kotlin coroutines, using `runblocking` within `transactiontemplate.execu...
Learnt from: chock-cho
PR: YAPP-Github/Gradmeet-BE#93
File: src/main/kotlin/com/dobby/backend/infrastructure/coroutine/TransactionCoroutineExecutor.kt:15-24
Timestamp: 2025-02-12T04:30:30.826Z
Learning: In Spring transactions with Kotlin coroutines, using `runBlocking` within `transactionTemplate.execute` ensures that the transaction context is active during the execution of suspend functions. While this approach blocks the thread, it guarantees transaction safety by preventing async operations from executing outside the transaction boundary.

Applied to files:

  • infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (2)
  • GitHub Check: Check Code Quality
  • GitHub Check: build

Comment on lines +1 to +29
package com.dobby.concurrency

import com.dobby.enums.MatchType
import com.dobby.enums.experiment.TimeSlot
import com.dobby.enums.member.GenderType
import com.dobby.enums.member.MemberStatus
import com.dobby.enums.member.ProviderType
import com.dobby.enums.member.RoleType
import com.dobby.gateway.OpenAiGateway
import com.dobby.gateway.UsageLimitGateway
import com.dobby.gateway.experiment.ExperimentPostKeywordsLogGateway
import com.dobby.gateway.member.MemberGateway
import com.dobby.model.experiment.keyword.ApplyMethodKeyword
import com.dobby.model.experiment.keyword.ExperimentPostKeywords
import com.dobby.model.experiment.keyword.TargetGroupKeyword
import com.dobby.model.member.Member
import com.dobby.usecase.experiment.ExtractExperimentPostKeywordsUseCase
import com.dobby.util.IdGenerator
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ActiveProfiles
import java.time.LocalDateTime
import java.util.concurrent.atomic.AtomicInteger

Copy link

@coderabbitai coderabbitai bot Aug 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

누락된 import 추가 필요

테스트 실행을 위해 필요한 import가 누락되어 있습니다.

 import com.dobby.util.IdGenerator
+import com.dobby.exception.experiment.ExperimentPostKeywordsDailyLimitExceededException
 import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
 import org.junit.jupiter.api.extension.ExtendWith

추가로 다음 import도 필요합니다:

 import java.util.concurrent.atomic.AtomicInteger
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
+import kotlin.test.assertEquals
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
package com.dobby.concurrency
import com.dobby.enums.MatchType
import com.dobby.enums.experiment.TimeSlot
import com.dobby.enums.member.GenderType
import com.dobby.enums.member.MemberStatus
import com.dobby.enums.member.ProviderType
import com.dobby.enums.member.RoleType
import com.dobby.gateway.OpenAiGateway
import com.dobby.gateway.UsageLimitGateway
import com.dobby.gateway.experiment.ExperimentPostKeywordsLogGateway
import com.dobby.gateway.member.MemberGateway
import com.dobby.model.experiment.keyword.ApplyMethodKeyword
import com.dobby.model.experiment.keyword.ExperimentPostKeywords
import com.dobby.model.experiment.keyword.TargetGroupKeyword
import com.dobby.model.member.Member
import com.dobby.usecase.experiment.ExtractExperimentPostKeywordsUseCase
import com.dobby.util.IdGenerator
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ActiveProfiles
import java.time.LocalDateTime
import java.util.concurrent.atomic.AtomicInteger
package com.dobby.concurrency
import com.dobby.enums.MatchType
import com.dobby.enums.experiment.TimeSlot
import com.dobby.enums.member.GenderType
import com.dobby.enums.member.MemberStatus
import com.dobby.enums.member.ProviderType
import com.dobby.enums.member.RoleType
import com.dobby.gateway.OpenAiGateway
import com.dobby.gateway.UsageLimitGateway
import com.dobby.gateway.experiment.ExperimentPostKeywordsLogGateway
import com.dobby.gateway.member.MemberGateway
import com.dobby.model.experiment.keyword.ApplyMethodKeyword
import com.dobby.model.experiment.keyword.ExperimentPostKeywords
import com.dobby.model.experiment.keyword.TargetGroupKeyword
import com.dobby.model.member.Member
import com.dobby.usecase.experiment.ExtractExperimentPostKeywordsUseCase
import com.dobby.util.IdGenerator
+import com.dobby.exception.experiment.ExperimentPostKeywordsDailyLimitExceededException
import org.junit.jupiter.api.BeforeEach
+import org.junit.jupiter.api.Test
import org.junit.jupiter.api.extension.ExtendWith
import org.mockito.junit.jupiter.MockitoExtension
import org.mockito.kotlin.any
import org.mockito.kotlin.mock
import org.mockito.kotlin.whenever
import org.springframework.boot.test.context.SpringBootTest
import org.springframework.test.context.ActiveProfiles
import java.time.LocalDateTime
import java.util.concurrent.atomic.AtomicInteger
+import java.util.concurrent.Executors
+import java.util.concurrent.TimeUnit
+import kotlin.test.assertEquals
🤖 Prompt for AI Agents
In
infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt
at the beginning of the file (lines 1 to 29), there are missing import
statements required for the test to run correctly. Add the necessary import
statements that are currently omitted to ensure all dependencies and annotations
used in the test class are properly imported.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FE에서 자동완성 기능 개발을 완료할 때까지 사용 횟수 제한을 풀어달라고 요청을 해서 임시로 관련 기능/테스트 코드는 주석처리한 상태야~

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ji-soo708 아, 그런 상황이었군요! FE 팀의 자동완성 기능 개발 완료를 기다리는 동안 임시로 사용 횟수 제한을 비활성화한 거네요.

그렇다면 제가 지적한 missing import 문제는 현재로서는 해결할 필요가 없겠습니다. 테스트 코드가 주석처리되어 있는 상태에서는 해당 import들이 불필요하니까요.

나중에 FE 팀의 자동완성 기능 개발이 완료되어 사용 횟수 제한을 다시 활성화할 때, 그때 테스트 코드의 주석을 해제하시면서 필요한 import들을 추가하시면 될 것 같습니다.

임시 조치에 대한 명확한 설명 감사합니다! 🙂


🧠 Learnings used
Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#150
File: infrastructure/src/main/kotlin/com/dobby/external/prompt/ExperimentPostKeywordMapper.kt:52-58
Timestamp: 2025-07-17T08:06:16.021Z
Learning: AI가 텍스트에서 키워드를 추출하는 과정에서 enum 변환 실패(IllegalArgumentException)는 정상적인 상황에 가깝다. 따라서 ExperimentPostKeywordMapper에서 TimeSlot, MatchType 등의 enum 변환 실패 시 로깅을 추가하지 않는 것이 적절하다.

Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#154
File: application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt:33-46
Timestamp: 2025-07-27T12:26:47.814Z
Learning: Gradmeet-BE 프로젝트에서 하루 최대 2회 사용 제한이 있는 기능의 경우, unique constraint나 낙관적 락 대신 DB 조회 기반 검증 방식을 선호한다. 분산 락은 나중에 최적화가 필요할 때 고려한다.

Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#150
File: infrastructure/src/main/kotlin/com/dobby/external/feign/openAi/OpenAiFeignClient.kt:10-14
Timestamp: 2025-07-17T08:06:13.596Z
Learning: Ji-soo708의 팀은 현재 OpenAI 공식 API만 사용할 예정이므로, FeignClient URL을 외부화하지 않고 하드코딩하는 것을 선호한다. 팀의 요구사항에 따라 단순함을 우선시하는 접근 방식을 취한다.

Learnt from: chock-cho
PR: YAPP-Github/Gradmeet-BE#148
File: domain/src/main/kotlin/com/dobby/enums/University.kt:288-296
Timestamp: 2025-07-12T18:17:29.186Z
Learning: 사용자 chock-cho는 자동완성 API의 서버 부하를 줄이기 위해 FE와 합의하에 디바운싱 처리로 설계했고, 사용자가 입력하지 않은 상태에서의 의도치 않은 API 호출을 방지하기 위해 @NotBlank 어노테이션을 적용했다. 사용자 행동 패턴까지 고려한 세심한 BE 설계 접근을 보여준다.

Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#140
File: domain/src/main/kotlin/com/dobby/gateway/auth/GoogleAuthGateway.kt:7-7
Timestamp: 2025-06-04T09:02:40.657Z
Learning: Ji-soo708의 팀은 로컬 ktlint 기준과 GitHub ktlint 체크 기준이 다를 때, 기존 코드베이스와의 일관성을 위해 로컬 기준을 우선시한다.

Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#154
File: infrastructure/src/main/kotlin/com/dobby/mapper/ExperimentPostKeywordsLogMapper.kt:15-22
Timestamp: 2025-07-27T12:37:15.372Z
Learning: Ji-soo708의 팀에서는 JSON 역직렬화 시 예외를 catch하여 래핑하기보다는, 예외를 자연스럽게 상위로 전파시켜 원본 컨텍스트를 보존하고 후속 조치를 용이하게 하는 것을 선호한다.

Comment on lines +109 to +149
// @Test
// fun `동시에 여러 요청 시 최대 2번까지만 성공하고 나머지는 제한 예외가 발생해야 한다`() {
// val executor = Executors.newFixedThreadPool(THREAD_COUNT)
//
// val successCount = mutableListOf<Unit>()
// val failCount = mutableListOf<Unit>()
// val lock = Any()
//
// repeat(THREAD_COUNT) {
// executor.submit {
// executeKeywordExtraction(successCount, failCount, lock)
// }
// }
//
// executor.shutdown()
// val finished = executor.awaitTermination(10, TimeUnit.SECONDS)
// if (!finished) {
// throw RuntimeException("Thread pool shutdown timeout occurred")
// }
//
// assertEquals(DAILY_LIMIT, successCount.size)
// assertEquals(THREAD_COUNT - DAILY_LIMIT, failCount.size)
// }
//
// private fun executeKeywordExtraction(
// successCount: MutableList<Unit>,
// failCount: MutableList<Unit>,
// lock: Any
// ) {
// try {
// val input = ExtractExperimentPostKeywordsUseCase.Input(memberId, text)
// useCase.execute(input)
// synchronized(lock) {
// successCount.add(Unit)
// }
// } catch (e: ExperimentPostKeywordsDailyLimitExceededException) {
// synchronized(lock) {
// failCount.add(Unit)
// }
// }
// }
Copy link

@coderabbitai coderabbitai bot Aug 2, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue

주석 처리된 테스트 코드 활성화 필요

PR 목적이 동시성 문제 해결인데 관련 테스트가 주석 처리되어 있습니다. 모킹 기반 테스트라도 동시성 검증을 위해 활성화해야 합니다.

-//    @Test
-//    fun `동시에 여러 요청 시 최대 2번까지만 성공하고 나머지는 제한 예외가 발생해야 한다`() {
+    @Test
+    fun `동시에 여러 요청 시 최대 2번까지만 성공하고 나머지는 제한 예외가 발생해야 한다`() {

테스트 전체를 주석 해제하여 동시성 문제 해결을 검증할 수 있도록 해주세요.

Committable suggestion skipped: line range outside the PR's diff.

🤖 Prompt for AI Agents
In
infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt
from lines 109 to 149, the entire concurrency test code is commented out, which
prevents verification of the concurrency issue fix. Remove the comment markers
to reactivate the test and ensure it runs during testing to validate the
concurrency behavior as intended.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FE에서 자동완성 기능 개발을 완료할 때까지 사용 횟수 제한을 풀어달라고 요청을 해서 임시로 관련 기능/테스트 코드는 주석처리한 상태야~

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Ji-soo708, 이해했습니다! FE 팀의 자동완성 기능 개발 완료를 기다리기 위해 임시로 사용 횟수 제한을 비활성화한 상태군요.

동시성 문제 해결을 위한 Redis INCR 로직은 구현되어 있고, 테스트 코드도 준비되어 있으니 FE 개발이 완료되면 주석을 해제하여 다시 활성화하면 되겠네요. 비즈니스 요구사항에 맞춘 합리적인 접근 방식입니다.


✏️ Learnings added
Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#162
File: infrastructure/src/test/kotlin/com/dobby/concurrency/ExtractExperimentPostKeywordsConcurrencyTest.kt:109-149
Timestamp: 2025-08-02T13:37:08.629Z
Learning: Gradmeet-BE 프로젝트에서 FE 팀의 자동완성 기능 개발 완료를 기다리기 위해 사용 횟수 제한 기능과 관련 테스트 코드를 임시로 주석 처리한 상태이다. 동시성 문제 해결을 위한 Redis INCR 로직은 구현되어 있고, FE 개발 완료 후 다시 활성화할 예정이다.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#150
File: infrastructure/src/main/kotlin/com/dobby/external/prompt/ExperimentPostKeywordMapper.kt:52-58
Timestamp: 2025-07-17T08:06:16.021Z
Learning: AI가 텍스트에서 키워드를 추출하는 과정에서 enum 변환 실패(IllegalArgumentException)는 정상적인 상황에 가깝다. 따라서 ExperimentPostKeywordMapper에서 TimeSlot, MatchType 등의 enum 변환 실패 시 로깅을 추가하지 않는 것이 적절하다.

Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#154
File: application/src/main/kotlin/com/dobby/usecase/experiment/ExtractExperimentPostKeywordsUseCase.kt:33-46
Timestamp: 2025-07-27T12:26:47.814Z
Learning: Gradmeet-BE 프로젝트에서 하루 최대 2회 사용 제한이 있는 기능의 경우, unique constraint나 낙관적 락 대신 DB 조회 기반 검증 방식을 선호한다. 분산 락은 나중에 최적화가 필요할 때 고려한다.

Learnt from: chock-cho
PR: YAPP-Github/Gradmeet-BE#148
File: domain/src/main/kotlin/com/dobby/enums/University.kt:288-296
Timestamp: 2025-07-12T18:17:29.186Z
Learning: 사용자 chock-cho는 자동완성 API의 서버 부하를 줄이기 위해 FE와 합의하에 디바운싱 처리로 설계했고, 사용자가 입력하지 않은 상태에서의 의도치 않은 API 호출을 방지하기 위해 @NotBlank 어노테이션을 적용했다. 사용자 행동 패턴까지 고려한 세심한 BE 설계 접근을 보여준다.

Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#140
File: domain/src/main/kotlin/com/dobby/gateway/auth/GoogleAuthGateway.kt:7-7
Timestamp: 2025-06-04T09:02:40.657Z
Learning: Ji-soo708의 팀은 로컬 ktlint 기준과 GitHub ktlint 체크 기준이 다를 때, 기존 코드베이스와의 일관성을 위해 로컬 기준을 우선시한다.

Learnt from: Ji-soo708
PR: YAPP-Github/Gradmeet-BE#154
File: infrastructure/src/main/kotlin/com/dobby/mapper/ExperimentPostKeywordsLogMapper.kt:15-22
Timestamp: 2025-07-27T12:37:15.372Z
Learning: Ji-soo708의 팀에서는 JSON 역직렬화 시 예외를 catch하여 래핑하기보다는, 예외를 자연스럽게 상위로 전파시켜 원본 컨텍스트를 보존하고 후속 조치를 용이하게 하는 것을 선호한다.

@Ji-soo708 Ji-soo708 changed the title [YS-528] [YS-532] refactor: 실험 공고 키워드 자동완성 동시성 문제 해결을 위한 Redis INCR 연산 로직 추가 [YS-532] refactor: 실험 공고 키워드 자동완성 동시성 문제 해결을 위한 Redis INCR 연산 로직 추가 Aug 2, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
⚙️ CHORE config, workflow.yaml ♻️ REFACTORING 리팩토링
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants