Skip to content

feat: add Redis/Kafka boilerplate for distributed environment migration - #53

Merged
Junkov0 merged 2 commits into
developfrom
feature/problem-refactor
Jul 31, 2026
Merged

Junkov0 merged 2 commits into
developfrom
feature/problem-refactor

Conversation

@Junkov0

@Junkov0 Junkov0 commented Jul 31, 2026

Copy link
Copy Markdown
Collaborator

작업 내용

  • 현재 momogo-api/realtime/batch가 EC2 단일 인스턴스 전제로 설계되어 있어,
    서버를 여러 대로 늘리는 순간 JWT 세션, SSE 알림, 배치 스케줄러가 인스턴스별로
    따로 동작해 깨지는 문제가 있음. 이번 작업은 그 해결에 필요한 Redis/Kafka
    인프라를 팀 공용으로 미리 잡아둔 보일러플레이트임 (실제 비즈니스 로직 교체는 별도 작업).

변경 사항

  • momogo-core에 Redis/Kafka 의존성 추가 → api/realtime/batch 전체에 자동 전파
  • RedisConfig: 공용 RedisTemplate<String, Object> 빈 추가 (JSON 직렬화)
  • KafkaConfig: 전체 @KafkaListener 기본 재시도(4회, exponential backoff) + DLT 격리 정책 추가
  • KafkaTopics: 토픽명 상수 클래스 추가 (하드코딩으로 인한 발행-구독 불일치 방지)
  • momogo-batch에 ShedLock(Redis 기반) 추가, BatchScheduler/ExpiredUserCleanupSchedule @SchedulerLock 적용 → 배치 인스턴스가 여러 대여도 스케줄 중복 실행 안 되게
  • 루트 docker-compose.yml 추가 (Redis, Kafka, Kafka UI) — 로컬 개발 환경 통일
    • api/realtime/batch application.yamlspring.data.redis.*, spring.kafka.* 설정 추가
      (전부 env var 기반, 로컬 기본값 포함이라 별도 설

체크리스트

  • 테스트 코드 작성 완료
  • 리뷰어 지정 완료

참고 사항

관련 이슈

Summary by CodeRabbit

  • 새 기능

    • Redis와 Kafka 기반 메시지 처리 및 실시간 기능을 지원합니다.
    • 알림 이벤트 처리와 장애 발생 시 자동 재시도 및 격리를 지원합니다.
    • 여러 인스턴스에서 예약 작업이 중복 실행되지 않도록 개선했습니다.
  • 개선 사항

    • momogo.kro.kr 접속을 지원하고 서비스 간 통신 안정성을 높였습니다.
    • Redis 기반 캐싱 및 작업 조정 기능을 추가했습니다.
  • 테스트

    • AI 문제 생성 기능의 부하·지속성·스트레스 테스트 결과를 최신 실행 데이터로 갱신했습니다.

@SungHuii

Copy link
Copy Markdown
Collaborator

@coderabbitai

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

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

Next review available in: 30 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: 21eadc2d-ac92-4f46-9d80-6a6167a2bb0d

📥 Commits

Reviewing files that changed from the base of the PR and between 3ae75af and eefef43.

📒 Files selected for processing (6)
  • k6/problem-ai/load-result.json
  • k6/problem-ai/soak-result.json
  • k6/problem-ai/spike-result.json
  • k6/problem-ai/stress-result.json
  • momogo-batch/src/main/java/com/momogo/batch/config/ShedLockConfig.java
  • momogo-core/src/main/java/com/momogo/core/common/config/KafkaConfig.java
📝 Walkthrough

Walkthrough

Redis와 Kafka 기반 인프라를 추가했습니다. 배치 작업에 Redis 분산 락을 적용했습니다. API CORS와 서비스 연결 설정을 갱신했습니다. Problem-AI k6 테스트 대상과 실행 결과를 업데이트했습니다.

Changes

플랫폼 인프라 구성

Layer / File(s) Summary
로컬 Redis·Kafka 스택
docker-compose.yml
Redis, 단일 노드 Kafka, Kafka UI 서비스를 추가했습니다. 각 서비스의 포트, 연결 주소, 의존성을 구성했습니다.
공용 Redis·Kafka 계약
momogo-core/build.gradle, momogo-core/src/main/java/com/momogo/core/common/config/*
RedisTemplate, notification-events 토픽 상수, Kafka 재시도 토픽 구성을 추가했습니다. Redis와 Kafka 관련 공용 의존성을 추가했습니다.
서비스 런타임 연결
momogo-api/src/main/resources/application.yaml, momogo-batch/src/main/resources/application.yaml, momogo-realtime/src/main/resources/application.yaml, momogo-api/src/main/java/.../SecurityConfig.java
각 서비스에 Redis·Kafka 연결 설정을 추가했습니다. momogo.kro.kr 도메인을 CORS 허용 출처에 추가했습니다.

배치 스케줄러 분산 락

Layer / File(s) Summary
ShedLock Redis provider
momogo-batch/build.gradle, momogo-batch/src/main/java/com/momogo/batch/config/ShedLockConfig.java
ShedLock 의존성을 추가했습니다. Redis 기반 LockProvider를 등록하고 기본 최대 잠금 시간을 30분으로 설정했습니다.
스케줄러 작업 잠금
momogo-batch/src/main/java/com/momogo/batch/scheduler/*
일간 리포트, 주간 리포트, 만료 사용자 정리 작업에 고유한 SchedulerLock을 적용했습니다.

Problem-AI 부하 테스트 갱신

Layer / File(s) Summary
테스트 대상 설정
k6/problem-ai/config.js
테스트 기본 URL과 SPACE_ID, CATEGORY_ID를 새 값으로 변경했습니다.
부하 테스트 결과
k6/problem-ai/*-result.json
load, soak, spike, stress 실행의 체크 결과, 요청 메트릭, 지연 시간, 오류율, 토큰 값을 새 실행 결과로 교체했습니다.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Possibly related PRs

Suggested reviewers: sunghuii

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 37.50% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed 제목은 분산 환경 전환을 위한 Redis 및 Kafka 보일러플레이트 추가라는 PR의 주요 변경 사항을 명확하고 간결하게 설명합니다.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/problem-refactor

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.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Actionable comments posted: 6

🧹 Nitpick comments (4)
momogo-core/src/main/java/com/momogo/core/common/config/KafkaConfig.java (1)

10-12: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

재시도 횟수와 DLT 이름 설명을 실제 설정과 일치시키세요.

maxAttempts(4)는 최초 처리 1회를 포함한 총 4회 처리입니다. 따라서 지연 재시도는 1초, 2초, 4초의 3회입니다. 기본 DLT 접미사는 ".DLT"가 아니라 "-dlt"입니다.

4회의 지연 재시도가 요구사항이면 maxAttempts(5)로 변경하세요. 총 4회 처리가 요구사항이면 JavaDoc을 수정하세요. Spring Kafka 관리 버전에서 동작을 확인하세요. (docs.spring.io)

Also applies to: 20-22

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@momogo-core/src/main/java/com/momogo/core/common/config/KafkaConfig.java`
around lines 10 - 12, KafkaConfig의 공통 재시도/DLT 정책 JavaDoc을 실제 설정과 일치시키세요.
maxAttempts(4)가 최초 처리 포함 총 4회 처리인지 확인해 지연 재시도 횟수를 3회로 설명하고, 기본 DLT 접미사를 ".DLT"가
아닌 "-dlt"로 수정하세요. 요구사항이 지연 재시도 4회라면 관련 설정을 maxAttempts(5)로 변경하고, 해당 Spring Kafka
버전의 동작과 일치하는지 검증하세요.
momogo-batch/src/main/java/com/momogo/batch/config/ShedLockConfig.java (3)

18-20: 🗄️ Data Integrity & Integration | 🔵 Trivial

운영 Redis의 장애 모델을 확인하세요.

RedisLockProvider는 Redis 장애나 master failover 이후 잠금 상태를 잃을 수 있습니다. 이 경우 여러 배치 인스턴스가 동시에 실행될 수 있습니다. 운영 Redis 토폴로지를 확인하세요. 중복 실행이 허용되지 않으면 작업의 멱등성 또는 fencing 전략을 추가하고, 필요하면 더 강한 일관성의 잠금 저장소를 검토하세요. (github.com)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@momogo-batch/src/main/java/com/momogo/batch/config/ShedLockConfig.java`
around lines 18 - 20, Review the Redis topology and failure behavior used by
lockProvider, including master failover and lock-state loss scenarios. If
duplicate batch execution is not acceptable, add an appropriate idempotency or
fencing strategy to the scheduled jobs, or replace RedisLockProvider with a lock
store that provides the required consistency guarantees.

18-20: 🗄️ Data Integrity & Integration | 🔵 Trivial | 🏗️ Heavy lift

Redis 기반 분산 락 통합 테스트를 추가하세요.

동일한 Redis와 잠금 이름을 사용하는 두 개의 batch ApplicationContext를 테스트하세요. 한 인스턴스만 작업 부수효과를 수행하고 다른 인스턴스는 건너뛰는지 검증하세요. 잠금 만료, Redis 재시작, 스케줄러 프록시 활성화도 검증하세요. ShedLock은 동일한 잠금 이름이 보유 중이면 다른 실행을 대기시키지 않고 건너뜁니다. (github.com)

PR 목표의 Test code is not yet completed 항목을 반영한 제안입니다.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@momogo-batch/src/main/java/com/momogo/batch/config/ShedLockConfig.java`
around lines 18 - 20, Redis 기반 분산 락의 통합 테스트를 추가하세요. ShedLockConfig의
lockProvider가 반환하는 동일한 Redis 연결과 잠금 이름을 공유하도록 두 개의 batch ApplicationContext를
구성하고, 한 인스턴스만 작업 부수효과를 수행하며 다른 인스턴스는 건너뛰는지 검증하세요. 잠금 만료와 Redis 재시작 후 재획득, 스케줄러
프록시 활성화 동작도 테스트하고, 잠금 보유 중 실행은 대기하지 않고 건너뛰는지 확인하세요.

10-12: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

분산 락의 보장 범위를 정확히 문서화하세요.

현재 문구의 한 번만 실행은 exactly-once 보장처럼 읽힙니다. ShedLock은 동일한 이름의 작업이 동시에 실행되는 것을 제한합니다. 잠금 만료나 Redis 장애 이후 재실행은 가능하므로 작업은 멱등해야 합니다. (github.com)

제안 수정
 /**
- * 배치 인스턴스가 여러 대로 늘어나도 `@Scheduled` 작업이 한 번만 실행되도록 하는 분산 락 설정.
+ * 동일한 잠금 이름의 `@Scheduled` 작업이 여러 인스턴스에서 동시에 실행되지 않도록 조정하는 분산 락 설정.
+ * 잠금 만료 또는 Redis 장애 시 재실행될 수 있으므로 작업은 멱등해야 한다.
  * 스케줄러 메서드에 `@SchedulerLock`(name = "...")을 붙이면 이 락이 적용된다.
  */
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@momogo-batch/src/main/java/com/momogo/batch/config/ShedLockConfig.java`
around lines 10 - 12, ShedLockConfig의 클래스 주석에서 스케줄 작업이 “한 번만 실행”된다는 표현을 제거하고,
동일한 락 이름의 작업에 대해 동시 실행만 제한한다고 명시하세요. 락 만료나 Redis 장애 후 재실행될 수 있으므로 작업이 멱등해야 한다는
요구사항도 함께 문서화하세요.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@docker-compose.yml`:
- Around line 16-17: Update the Kafka listener configuration in
docker-compose.yml to separate host and Docker-network endpoints: retain a
localhost listener for host clients and add an internal broker listener
advertised with the Kafka service hostname. Configure Kafka UI to use the
internal listener rather than localhost, and keep KAFKA_LISTENERS aligned with
both advertised endpoints.

In `@k6/problem-ai/config.js`:
- Around line 16-17: Update the BASE_URL configuration to use the valid
certificate-backed HTTPS endpoint instead of the public HTTP address, ensuring
load-test.js sends Authorization, X-XSRF-TOKEN, and Cookie headers only over
HTTPS.

In `@k6/problem-ai/load-result.json`:
- Around line 163-164: Remove the serialized setup_data authentication fields
authToken and csrfToken from k6/problem-ai/load-result.json lines 163-164,
k6/problem-ai/soak-result.json lines 132-134, k6/problem-ai/spike-result.json
lines 159-161, and k6/problem-ai/stress-result.json lines 166-168; update the
common result-generation flow to exclude or mask these sensitive values, and
revoke any exposed tokens and remove them from repository history if necessary.

In `@momogo-api/src/main/java/com/momogo/api/auth/config/SecurityConfig.java`:
- Around line 197-199: Remove the HTTP production origin "http://momogo.kro.kr"
from the credentialed CORS origins in SecurityConfig, retaining only
"https://momogo.kro.kr" for production while preserving the localhost origin.

In `@momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java`:
- Line 37: 각 스케줄러의 ShedLock 어노테이션에 업무 주기보다 충분히 짧은 lockAtLeastFor를 추가하세요.
momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java 37-37의
dailyReportJob에는 예시로 PT5M을 설정하고, 51-51의 weeklyReportJob과
momogo-batch/src/main/java/com/momogo/batch/scheduler/ExpiredUserCleanupScheduler.java
24-24의 expiredUserCleanupJob에도 적절한 최소 잠금 시간을 설정하되 기존 lockAtMostFor는 유지하세요.
- Line 37: Update the ShedLock TTLs on BatchScheduler.dailyReportJob
(BatchScheduler.java:37-37), BatchScheduler.weeklyReportJob
(BatchScheduler.java:51-51), and
ExpiredUserCleanupScheduler.expiredUserCleanupJob
(ExpiredUserCleanupScheduler.java:24-24) individually, replacing the fixed PT30M
values with durations exceeding each job’s measured P99 execution time plus
safety margin; base report jobs on createReports() and cleanup on
deleteExpiredUsers().

---

Nitpick comments:
In `@momogo-batch/src/main/java/com/momogo/batch/config/ShedLockConfig.java`:
- Around line 18-20: Review the Redis topology and failure behavior used by
lockProvider, including master failover and lock-state loss scenarios. If
duplicate batch execution is not acceptable, add an appropriate idempotency or
fencing strategy to the scheduled jobs, or replace RedisLockProvider with a lock
store that provides the required consistency guarantees.
- Around line 18-20: Redis 기반 분산 락의 통합 테스트를 추가하세요. ShedLockConfig의 lockProvider가
반환하는 동일한 Redis 연결과 잠금 이름을 공유하도록 두 개의 batch ApplicationContext를 구성하고, 한 인스턴스만 작업
부수효과를 수행하며 다른 인스턴스는 건너뛰는지 검증하세요. 잠금 만료와 Redis 재시작 후 재획득, 스케줄러 프록시 활성화 동작도 테스트하고,
잠금 보유 중 실행은 대기하지 않고 건너뛰는지 확인하세요.
- Around line 10-12: ShedLockConfig의 클래스 주석에서 스케줄 작업이 “한 번만 실행”된다는 표현을 제거하고, 동일한
락 이름의 작업에 대해 동시 실행만 제한한다고 명시하세요. 락 만료나 Redis 장애 후 재실행될 수 있으므로 작업이 멱등해야 한다는 요구사항도
함께 문서화하세요.

In `@momogo-core/src/main/java/com/momogo/core/common/config/KafkaConfig.java`:
- Around line 10-12: KafkaConfig의 공통 재시도/DLT 정책 JavaDoc을 실제 설정과 일치시키세요.
maxAttempts(4)가 최초 처리 포함 총 4회 처리인지 확인해 지연 재시도 횟수를 3회로 설명하고, 기본 DLT 접미사를 ".DLT"가
아닌 "-dlt"로 수정하세요. 요구사항이 지연 재시도 4회라면 관련 설정을 maxAttempts(5)로 변경하고, 해당 Spring Kafka
버전의 동작과 일치하는지 검증하세요.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro Plus

Run ID: fc7ae5ed-1278-4bc4-a381-6399930bae90

📥 Commits

Reviewing files that changed from the base of the PR and between ee08607 and 3ae75af.

📒 Files selected for processing (18)
  • docker-compose.yml
  • k6/problem-ai/config.js
  • k6/problem-ai/load-result.json
  • k6/problem-ai/soak-result.json
  • k6/problem-ai/spike-result.json
  • k6/problem-ai/stress-result.json
  • momogo-api/src/main/java/com/momogo/api/auth/config/SecurityConfig.java
  • momogo-api/src/main/resources/application.yaml
  • momogo-batch/build.gradle
  • momogo-batch/src/main/java/com/momogo/batch/config/ShedLockConfig.java
  • momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java
  • momogo-batch/src/main/java/com/momogo/batch/scheduler/ExpiredUserCleanupScheduler.java
  • momogo-batch/src/main/resources/application.yaml
  • momogo-core/build.gradle
  • momogo-core/src/main/java/com/momogo/core/common/config/KafkaConfig.java
  • momogo-core/src/main/java/com/momogo/core/common/config/KafkaTopics.java
  • momogo-core/src/main/java/com/momogo/core/common/config/RedisConfig.java
  • momogo-realtime/src/main/resources/application.yaml

Comment thread docker-compose.yml
Comment on lines +16 to +17
KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092

@coderabbitai coderabbitai Bot Jul 31, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🎯 Functional Correctness | 🟠 Major | ⚡ Quick win

[중대] 컨테이너용 Kafka 리스너를 분리하세요.

KAFKA_ADVERTISED_LISTENERSlocalhost:9092만 반환합니다. Kafka UI는 메타데이터를 받은 뒤 자기 컨테이너의 localhost:9092에 연결합니다. 따라서 Kafka UI가 브로커에 연결하지 못합니다.

호스트용 리스너와 Docker 네트워크용 리스너를 분리하세요. Kafka UI는 내부 리스너를 사용해야 합니다.

수정 예시
-      KAFKA_LISTENERS: PLAINTEXT://:9092,CONTROLLER://:9093
-      KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
+      KAFKA_LISTENERS: HOST://:9092,INTERNAL://:29092,CONTROLLER://:9093
+      KAFKA_ADVERTISED_LISTENERS: HOST://localhost:9092,INTERNAL://kafka:29092
       KAFKA_CONTROLLER_LISTENER_NAMES: CONTROLLER
       KAFKA_CONTROLLER_QUORUM_VOTERS: 1@kafka:9093
-      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT
-      KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
+      KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: CONTROLLER:PLAINTEXT,HOST:PLAINTEXT,INTERNAL:PLAINTEXT
+      KAFKA_INTER_BROKER_LISTENER_NAME: INTERNAL
...
-      KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092
+      KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:29092
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@docker-compose.yml` around lines 16 - 17, Update the Kafka listener
configuration in docker-compose.yml to separate host and Docker-network
endpoints: retain a localhost listener for host clients and add an internal
broker listener advertised with the Kafka service hostname. Configure Kafka UI
to use the internal listener rather than localhost, and keep KAFKA_LISTENERS
aligned with both advertised endpoints.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

현재 보일러 플레이트용 구성을 한 상태입니다. 추후 kafka 리스너를 구현하고 적용하면서 수정하도록 하겠습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@SungHuii, 확인했습니다. 현재 PR의 보일러플레이트 범위에서는 이 항목을 보류하겠습니다.

Kafka 리스너를 적용하는 작업 시점에는 호스트용 엔드포인트와 Docker 네트워크용 엔드포인트를 분리해야 합니다. 그렇지 않으면 Kafka UI와 같은 컨테이너 클라이언트가 localhost:9092로 연결을 시도할 수 있습니다.

이 작업을 추적할 GitHub 후속 이슈를 생성할까요?

🐇

You are interacting with an AI system.

Comment thread k6/problem-ai/config.js
Comment on lines +16 to +17
// 1. [서버 주소] EC2 + Nginx (momogo.kro.kr)
export const BASE_URL = 'http://momogo.kro.kr';

@coderabbitai coderabbitai Bot Jul 31, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

[심각] 인증 요청에 HTTPS를 사용하세요.

load-test.js의 요청은 Authorization, X-XSRF-TOKEN, Cookie 헤더를 전송합니다. 현재 공개 HTTP 주소를 사용하므로 네트워크 구간에서 인증 정보가 노출될 수 있습니다.

유효한 인증서가 설정된 HTTPS 주소를 사용하세요.

🔐 변경 예시
-export const BASE_URL = 'http://momogo.kro.kr';
+export const BASE_URL = 'https://momogo.kro.kr';
📝 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
// 1. [서버 주소] EC2 + Nginx (momogo.kro.kr)
export const BASE_URL = 'http://momogo.kro.kr';
// 1. [서버 주소] EC2 + Nginx (momogo.kro.kr)
export const BASE_URL = 'https://momogo.kro.kr';
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@k6/problem-ai/config.js` around lines 16 - 17, Update the BASE_URL
configuration to use the valid certificate-backed HTTPS endpoint instead of the
public HTTP address, ensuring load-test.js sends Authorization, X-XSRF-TOKEN,
and Cookie headers only over HTTPS.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

이 부분은 아직 HTTPS 설정이 되어있지 않습니다. 추후 HTTPS를 구성한 후 해결하도록 하겠습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@SungHuii, 확인했습니다. HTTPS 설정은 별도 작업으로 진행해 주세요. 인프라 구성이 끝나면 BASE_URL 값을 https://momogo.kro.kr로 변경해 주세요. 이 항목은 나중에 처리하는 것으로 남겨두겠습니다.

(๑•̀ㅁ•́๑) 응원합니다, 화이팅!

You are interacting with an AI system.

Comment thread k6/problem-ai/load-result.json Outdated
Comment on lines +197 to +199
"http://localhost:5173",
"http://momogo.kro.kr",
"https://momogo.kro.kr"

@coderabbitai coderabbitai Bot Jul 31, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🔒 Security & Privacy | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

rg -n -i -C 4 \
  'momogo\.kro\.kr|allowedOrigins|setAllowCredentials|strict-transport-security|hsts|set-cookie|responsecookie|samesite|setsecure|secure\s*\(' \
  .

Repository: MoMoGo-QuizPlatform/MoMoGo

Length of output: 16613


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== SecurityConfig security / cors sections =="
sed -n '160,245p' momogo-api/src/main/java/com/momogo/api/auth/config/SecurityConfig.java

echo
echo "== JwtTokenProvider cookie creation section =="
sed -n '240,265p' momogo-api/src/main/java/com/momogo/api/auth/jwt/JwtTokenProvider.java

echo
echo "== application property files with jwt cors / cookie settings =="
rg -n -i 'jwt|cors|refresh-token.cookie|cors' -g 'application*.properties' -g 'application*.yml' .

Repository: MoMoGo-QuizPlatform/MoMoGo

Length of output: 3610


🏁 Script executed:

#!/bin/bash
set -euo pipefail

python3 - <<'PY'
from pathlib import Path
p = Path('momogo-api/src/main/java/com/momogo/api/auth/config/SecurityConfig.java')
text = p.read_text()
print('SecurityConfig.java path exists:', p.exists())
for needle in [
    'setAllowCredentials(true)',
    '"http://localhost:5173"',
    '"http://momogo.kro.kr"',
    '"https://momogo.kro.kr"',
    'strict-transport-security',
    'hsts',
]:
    print(f'{needle!r}:', needle in text)

# Extract CORS origin/security settings using simple line-scanning.
origins = []
allow_credentials = None
for line in text.splitlines():
    stripped = line.strip()
    if 'setAllowedOrigins' in stripped:
        continue
    if 'setAllowCredentials' in stripped:
        allow_credentials = 'true' in stripped
    if '"' in stripped:
        origin = stripped.strip().strip(',').strip('"').strip()
        if origin and (origin.startswith('http://') or origin.startswith('https://')):
            origins.append(origin)
print('extracted_http_origins:', [o for o in origins if o.startswith('http://')])
print('extracted_https_origins:', [o for o in origins if o.startswith('https://')])
print('allow_credentials:', allow_credentials)
PY

Repository: MoMoGo-QuizPlatform/MoMoGo

Length of output: 529


[중대] 자격 증명 허용 CORS에서 HTTP 운영 Origin을 제거하세요.

http://momogo.kro.kr는 암호화되지 않은 외부 Origin입니다. setAllowCredentials(true)가 있는 CORS 설정에서 HTTP 운영 Origin을 허용하면, 브라우저가 자격 증명을 포함할 때 공격자가 스나이핑한 HTTP 트래픽에서 스크립트가 운영 도메인 API 요청을 실행할 수 있습니다.

운영 CORS에는 https://momogo.kro.kr만 유지하세요. HTTP에서 HTTPS로의 리다이렉트와 HSTS는 배포 프록시/TLS 종료 지점에서 적용하고, 인증 쿠키의 SecureSameSite 속성도 함께 확인하세요.

수정 예시
         configuration.setAllowedOrigins(List.of(
                 "http://localhost:5173",
-                "http://momogo.kro.kr",
                 "https://momogo.kro.kr"
         ));
📝 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
"http://localhost:5173",
"http://momogo.kro.kr",
"https://momogo.kro.kr"
"http://localhost:5173",
"https://momogo.kro.kr"
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@momogo-api/src/main/java/com/momogo/api/auth/config/SecurityConfig.java`
around lines 197 - 199, Remove the HTTP production origin "http://momogo.kro.kr"
from the credentialed CORS origins in SecurityConfig, retaining only
"https://momogo.kro.kr" for production while preserving the localhost origin.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

이 부분은 아직 HTTPS 설정이 되어있지 않습니다. 추후 HTTPS를 구성한 후 해결하도록 하겠습니다.

@Junkov0 Junkov0 Jul 31, 2026

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

이 부분은 팀원의 말처럼 아직 HTTPS 설정이 되어있지 않습니다. 추후 HTTPS를 구성한 후 해결하도록 하겠습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

Seems like the humans are having a chat. I'll hop back into my burrow for now. If you need me again, just tag @coderabbitai in a new comment, and I'll come hopping out!

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

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

@coderabbitai 그냥 나중에 해당 부분은 HTTPS가 구성되면 적용토록 하겠습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@Junkov0 확인했습니다. HTTPS 구성 전까지 이 보안 위험은 남아 있습니다.

HTTPS 구성 시 SecurityConfig에서 http://momogo.kro.kr를 제거하고, https://momogo.kro.kr만 자격 증명 허용 CORS Origin으로 유지해야 합니다. TLS 종료 지점의 HTTP→HTTPS 리다이렉트와 인증 쿠키의 Secure/SameSite 설정도 함께 확인하세요.

이 작업을 추적할 GitHub 후속 이슈를 생성할까요?

🐰 …

You are interacting with an AI system.


// 매일 00:10 - 어제 하루치 개인 일간 리포트 생성
@Scheduled(cron = "0 10 0 * * *")
@SchedulerLock(name = "dailyReportJob", lockAtMostFor = "PT30M")

@coderabbitai coderabbitai Bot Jul 31, 2026

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== candidate files =="
fd -a 'BatchScheduler\.java|ExpiredUserCleanupScheduler\.java' . || true

echo
echo "== imports and SchedulerLock usages =="
rg -n "SchedulerLock|shedlock|lockAtMostFor|lockAtLeastFor|CronTrigger|`@Scheduled`" -S . || true

echo
echo "== relevant source snippets =="
for f in $(fd 'BatchScheduler\.java|ExpiredUserCleanupScheduler\.java' .); do
  echo "--- $f"
  wc -l "$f"
  sed -n '1,120p' "$f" | cat -n
done

echo
echo "== dependency references for shedlock =="
fd -a 'build.gradle|build.gradle.kts|pom.xml|gradle.properties|settings.gradle|settings.gradle.kts' . | while read -r f; do
  echo "--- $f"
  rg -n "shedlock|ShedLock|scheduleLock|lockAtLeastFor|lockProvider|lock-store|mongodb|redis|consul|jdbc" "$f" || true
done

Repository: MoMoGo-QuizPlatform/MoMoGo

Length of output: 7409


🌐 Web query:

ShedLock lockAtLeastFor prevents repeated executions after job finishes lockAtMostFor duration

💡 Result:

Yes, that is correct. In ShedLock, the lock is normally released as soon as the task finishes [1][2]. However, if you specify the lockAtLeastFor attribute, ShedLock will explicitly hold the lock for at least that duration, preventing other nodes from executing the same task even if the original task has already completed [3][4][5]. The primary purpose of lockAtLeastFor is to ensure that a task is executed at most once within a given period [3][4]. This is particularly useful for short-running tasks where, due to clock synchronization differences between nodes, one node might otherwise perceive the lock as released and immediately trigger the task again [1][6][2]. By contrast, lockAtMostFor serves as a safety mechanism (a fallback) to ensure that if a node crashes or the JVM dies before the task completes, the lock will eventually be released after the specified duration, allowing other nodes to take over [3][1][2]. You should always set lockAtMostFor to a value significantly longer than the maximum expected execution time of your task; if a task runs longer than this duration, the behavior becomes unpredictable, potentially leading to multiple processes holding the lock simultaneously [1][6][2].

Citations:


🌐 Web query:

ShedLock SchedulerLock annotation lockAtLeastFor default lockAtMostFor release immediately after task done

💡 Result:

In ShedLock, the lock is released as soon as the task finishes, with one notable exception involving the lockAtLeastFor attribute [1][2][3]. Here is how the attributes function regarding lock release: 1. lockAtMostFor: This serves as a safety net [4][5]. If the node executing the task crashes or dies, the lock is guaranteed to be released after this duration [4][1][2]. You should set this to a value significantly longer than your task's maximum expected execution time to avoid premature expiration [1][2][3]. If a task takes longer than this duration, the behavior becomes unpredictable, as the lock might be acquired by another node [1][2][3]. If not specified in the @SchedulerLock annotation, the default value defined in @EnableSchedulerLock is used [6][2][3]. 2. lockAtLeastFor: This attribute mandates that the lock be held for at least the specified duration, even if the task completes earlier [4][1][2]. Its primary purpose is to prevent the task from being executed more than once in a given period in scenarios where task execution is very short and there is clock drift between nodes [1][2][3]. If this is set, the lock is not released immediately upon task completion; it is held until this minimum time has elapsed [7][8][9]. Under normal circumstances (without lockAtLeastFor), the library attempts to release the lock immediately upon the conclusion of the task [4][5][9]. There is no native configuration to override this to force an immediate release if lockAtLeastFor is active, as that would contradict the purpose of the setting [7][8].

Citations:


각 스케줄러에 lockAtLeastFor와 함께 최소 잠금 시간을 설정하세요.

lockAtMostFor는 장애 시 잠금이 자동 해제되도록 하는 상한 보호 설정입니다. 이 설정만 사용되면 작업이 끝나면 잠금이 바로 해제되므로, 짧은 실행 시간이나 노드 간 clock drift 때문에 같은 @Scheduled 크론 스팀의 재호출이 같은 잠금 이름으로 다시 실행될 수 있습니다. 이 작업들은 "하루/일주 단건 실행"이 목적이라 각 어노테이션에业务주기보다 충분히 짧은 최소 잠금 시간을 추가해 중복 실행을 막는 편이 안전합니다.

  • momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java#L37: dailyReportJoblockAtLeastFor = "PT5M"처럼 최소 잠금 시간을 추가하세요.
  • momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java#L51: weeklyReportJoblockAtLeastFor를 추가하세요.
  • momogo-batch/src/main/java/com/momogo/batch/scheduler/ExpiredUserCleanupScheduler.java#L24: expiredUserCleanupJob에도 최소 잠금 시간을 추가하세요.
📍 Affects 2 files
  • momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java#L37-L37 (this comment)
  • momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java#L51-L51
  • momogo-batch/src/main/java/com/momogo/batch/scheduler/ExpiredUserCleanupScheduler.java#L24-L24
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java` at
line 37, 각 스케줄러의 ShedLock 어노테이션에 업무 주기보다 충분히 짧은 lockAtLeastFor를 추가하세요.
momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java 37-37의
dailyReportJob에는 예시로 PT5M을 설정하고, 51-51의 weeklyReportJob과
momogo-batch/src/main/java/com/momogo/batch/scheduler/ExpiredUserCleanupScheduler.java
24-24의 expiredUserCleanupJob에도 적절한 최소 잠금 시간을 설정하되 기존 lockAtMostFor는 유지하세요.

🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

rg -n -C 8 'runDailyReportJob|runWeeklyReportJob|runExpiredUserCleanupJob|deleteExpiredUsers|`@Timed`|Timer|Observation' . --glob '*.java'

Repository: MoMoGo-QuizPlatform/MoMoGo

Length of output: 10124


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

# Locate and inspect the relevant scheduler/service implementations and any shedlock configuration references.
for f in \
  momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java \
  momogo-batch/src/main/java/com/momogo/batch/scheduler/ExpiredUserCleanupScheduler.java \
  momogo-core/src/main/java/com/momogo/core/domain/user/service/UserServiceImpl.java \
  momogo-batch/src/main/java/com/momogo/batch/job \
  .
do
  if [ -d "$f" ]; then
    echo "== files under $f =="
    git ls-files "$f" | sed -n '1,120p'
  elif [ -f "$f" ]; then
    echo "== outline $f =="
    ast-grep outline "$f" || true
    echo "== contents $f =="
    nl -ba "$f" | sed -n '1,220p'
  fi
done

echo "== shedlock mentions across repo =="
rg -n -i "shedlock|LockProvider|`@SchedulerLock`|lockAtMostFor|schedule" --glob '*.java' --glob 'pom.xml' --glob '*.yml' --glob '*.yaml' --glob '*.properties' .

Repository: MoMoGo-QuizPlatform/MoMoGo

Length of output: 519


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

for f in \
  momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java \
  momogo-batch/src/main/java/com/momogo/batch/scheduler/ExpiredUserCleanupScheduler.java \
  momogo-core/src/main/java/com/momogo/core/domain/user/service/UserServiceImpl.java \
  momogo-core/src/main/java/com/momogo/core/domain/user/service/UserHardDeleteProcessor.java \
  momogo-batch/src/main/java/com/momogo/batch/job \
  .
do
  if [ -d "$f" ]; then
    echo "== files under $f =="
    git ls-files "$f" | sed -n '1,160p'
  elif [ -f "$f" ]; then
    echo "== outline $f =="
    ast-grep outline "$f" || true
    echo "== contents $f =="
    awk '{printf "%6d\t%s\n", NR, $0}' "$f" | sed -n '1,240p'
  fi
done

echo "== shedlock mentions across repo =="
rg -n -i "shedlock|LockProvider|`@SchedulerLock`|lockAtMostFor|schedule|batch" --glob '*.java' --glob 'pom.xml' --glob '*.yml' --glob '*.yaml' --glob '*.properties' . || true

Repository: MoMoGo-QuizPlatform/MoMoGo

Length of output: 36769


🏁 Script executed:

#!/usr/bin/env bash
set -euo pipefail

echo "== PersonalReportBatchJobConfig =="
awk '{printf "%6d\t%s\n", NR, $0}' momogo-batch/src/main/java/com/momogo/batch/job/PersonalReportBatchJobConfig.java | sed -n '1,260p'

echo "== ShedLockConfig =="
awk '{printf "%6d\t%s\n", NR, $0}' momogo-batch/src/main/java/com/momogo/batch/config/ShedLockConfig.java | sed -n '1,80p'

echo "== batch deps =="
awk '{printf "%6d\t%s\n", NR, $0}' momogo-batch/build.gradle | sed -n '1,160p'

echo "== repo files under batch job =="
git ls-files momogo-batch/src/main/java/com/momogo/batch/job | sed -n '1,120p'

Repository: MoMoGo-QuizPlatform/MoMoGo

Length of output: 8439


고정된 PT30M을 각 배치 작업의 P99 실행 시간보다 길게 검증하세요.

ShedLock의 락 TTL은 작업 종료보다 먼저 만료되면 분산 환경에서 같은 스케줄을 가진 작업이 다시 실행될 수 있습니다. dailyReportJob, weeklyReportJob, expiredUserCleanupJob은 각각 집계/저장과 만료 회원 목록 조회 + 개별 삭제 경로를 모두 포함하므로 데이터 규모에 따라 30분이 부족할 수 있습니다. PT30M 대신 createReports() 또는 deleteExpiredUsers()의 P99 실행 시간 + 여유 시간을 반영한 값으로 개별 설정하세요.

📍 Affects 2 files
  • momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java#L37-L37 (this comment)
  • momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java#L51-L51
  • momogo-batch/src/main/java/com/momogo/batch/scheduler/ExpiredUserCleanupScheduler.java#L24-L24
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@momogo-batch/src/main/java/com/momogo/batch/scheduler/BatchScheduler.java` at
line 37, Update the ShedLock TTLs on BatchScheduler.dailyReportJob
(BatchScheduler.java:37-37), BatchScheduler.weeklyReportJob
(BatchScheduler.java:51-51), and
ExpiredUserCleanupScheduler.expiredUserCleanupJob
(ExpiredUserCleanupScheduler.java:24-24) individually, replacing the fixed PT30M
values with durations exceeding each job’s measured P99 execution time plus
safety margin; base report jobs on createReports() and cleanup on
deleteExpiredUsers().

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

추후 도메인 담당자가 수정하도록 하겠습니다.

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

@SungHuii, 확인했습니다. 현재 PR에서는 해당 검토 사항을 보류하겠습니다.

후속 작업에서는 각 배치 작업의 lockAtLeastFor 설정과 lockAtMostFor 적정 시간을 함께 검토해야 합니다. 필요하면 도메인 담당자에게 할당하는 GitHub 이슈를 생성하겠습니다. 생성할까요?

🐇 …

You are interacting with an AI system.

@coderabbitai

coderabbitai Bot commented Jul 31, 2026

Copy link
Copy Markdown

@SungHuii 검토를 시작합니다. Redis, Kafka, ShedLock 설정과 환경별 구성의 배포 영향을 중점적으로 확인하겠습니다.

✅ Action performed

Review finished.

Note: CodeRabbit is an incremental review system and does not re-review already reviewed commits. This command is applicable only when automatic reviews are paused.

@idktomorrow idktomorrow left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

고생 많으셨습니다! ❤️

@jaejo jaejo left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Good Job

@Junkov0
Junkov0 merged commit 3a7e516 into develop Jul 31, 2026
1 check passed
@Junkov0
Junkov0 deleted the feature/problem-refactor branch July 31, 2026 07:13
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.

4 participants