-
Notifications
You must be signed in to change notification settings - Fork 1
[FEAT] #143 kafka 도입 비동기 이벤트 기반 추천알림 로직 개발 #144
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: develop
Are you sure you want to change the base?
Changes from 5 commits
08c8253
ef4f42a
928bb00
edc783b
3a8a73f
10a813f
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| @@ -1,54 +1,101 @@ | ||||||||||||||
| services: | ||||||||||||||
| redis: | ||||||||||||||
| image: redis:7-alpine | ||||||||||||||
| container_name: redis | ||||||||||||||
| ports: | ||||||||||||||
| - "6379:6379" | ||||||||||||||
| restart: unless-stopped | ||||||||||||||
| mem_limit: 128m | ||||||||||||||
| command: redis-server --appendonly yes | ||||||||||||||
| volumes: | ||||||||||||||
| - redis_data:/data | ||||||||||||||
| # 블루 배포 | ||||||||||||||
| app-blue: | ||||||||||||||
| image: ddhi7/ccapp:latest #이미지는 동일 이미지 사용 : (깃허브 플젝 -> ccapp 이미지) | ||||||||||||||
| container_name: ccapp-blue | ||||||||||||||
| ports: | ||||||||||||||
| - "8081:8080" | ||||||||||||||
| env_file: | ||||||||||||||
| - .env | ||||||||||||||
| restart: unless-stopped | ||||||||||||||
| pull_policy: always | ||||||||||||||
| mem_limit: 400m | ||||||||||||||
| healthcheck: | ||||||||||||||
| test: [ "CMD", "curl", "-f", "http://localhost:8080/actuator/health" ] | ||||||||||||||
| interval: 30s | ||||||||||||||
| timeout: 10s | ||||||||||||||
| retries: 3 | ||||||||||||||
| start_period: 40s | ||||||||||||||
| depends_on: | ||||||||||||||
| - redis | ||||||||||||||
| services: | ||||||||||||||
| redis: | ||||||||||||||
| image: redis:7-alpine | ||||||||||||||
| container_name: redis | ||||||||||||||
| ports: | ||||||||||||||
| - "6379:6379" | ||||||||||||||
| restart: unless-stopped | ||||||||||||||
| mem_limit: 128m | ||||||||||||||
| command: redis-server --appendonly yes | ||||||||||||||
| volumes: | ||||||||||||||
| - redis_data:/data | ||||||||||||||
| # 블루 배포 | ||||||||||||||
| app-blue: | ||||||||||||||
| image: ddhi7/ccapp:latest #이미지는 동일 이미지 사용 : (깃허브 플젝 -> ccapp 이미지) | ||||||||||||||
| container_name: ccapp-blue | ||||||||||||||
| ports: | ||||||||||||||
| - "8081:8080" | ||||||||||||||
| env_file: | ||||||||||||||
| - .env | ||||||||||||||
| restart: unless-stopped | ||||||||||||||
| pull_policy: always | ||||||||||||||
| mem_limit: 400m | ||||||||||||||
| healthcheck: | ||||||||||||||
| test: [ "CMD", "curl", "-f", "http://localhost:8080/actuator/health" ] | ||||||||||||||
| interval: 30s | ||||||||||||||
| timeout: 10s | ||||||||||||||
| retries: 3 | ||||||||||||||
| start_period: 40s | ||||||||||||||
| depends_on: | ||||||||||||||
| - redis | ||||||||||||||
| - kafka #추가 | ||||||||||||||
|
|
||||||||||||||
| app-green: | ||||||||||||||
| #그린 배포 | ||||||||||||||
| image: ddhi7/ccapp:latest | ||||||||||||||
| container_name: ccapp-green | ||||||||||||||
| ports: | ||||||||||||||
| - "8082:8080" | ||||||||||||||
| env_file: | ||||||||||||||
| - .env | ||||||||||||||
| restart: unless-stopped | ||||||||||||||
| pull_policy: always | ||||||||||||||
| mem_limit: 400m | ||||||||||||||
| healthcheck: | ||||||||||||||
| test: [ "CMD", "curl", "-f", "http://localhost:8080/actuator/health" ] | ||||||||||||||
| interval: 30s | ||||||||||||||
| timeout: 10s | ||||||||||||||
| retries: 3 | ||||||||||||||
| start_period: 40s | ||||||||||||||
| depends_on: | ||||||||||||||
| - redis | ||||||||||||||
| app-green: | ||||||||||||||
| #그린 배포 | ||||||||||||||
| image: ddhi7/ccapp:latest | ||||||||||||||
| container_name: ccapp-green | ||||||||||||||
| ports: | ||||||||||||||
| - "8082:8080" | ||||||||||||||
| env_file: | ||||||||||||||
| - .env | ||||||||||||||
| restart: unless-stopped | ||||||||||||||
| pull_policy: always | ||||||||||||||
| mem_limit: 400m | ||||||||||||||
| healthcheck: | ||||||||||||||
| test: [ "CMD", "curl", "-f", "http://localhost:8080/actuator/health" ] | ||||||||||||||
| interval: 30s | ||||||||||||||
| timeout: 10s | ||||||||||||||
| retries: 3 | ||||||||||||||
| start_period: 40s | ||||||||||||||
| depends_on: | ||||||||||||||
| - redis | ||||||||||||||
| - kafka #추가 | ||||||||||||||
|
|
||||||||||||||
| volumes: | ||||||||||||||
| redis_data: | ||||||||||||||
| driver: local | ||||||||||||||
|
|
||||||||||||||
| kafka: | ||||||||||||||
| image: confluentinc/cp-kafka:latest | ||||||||||||||
| container_name: kafka | ||||||||||||||
| ports: | ||||||||||||||
| - "9092:9092" # 도커 내부 통신용 | ||||||||||||||
| - "29092:29092" # 로컬호스트 접속용 | ||||||||||||||
| environment: | ||||||||||||||
| # 필수 KRaft 설정 | ||||||||||||||
| CLUSTER_ID: "hjeeg3q1SoCw7IKoRw-rMQ" | ||||||||||||||
| KAFKA_NODE_ID: 1 | ||||||||||||||
| KAFKA_PROCESS_ROLES: "broker,controller" # 브로커와 컨트롤러 역할 | ||||||||||||||
| KAFKA_CONTROLLER_QUORUM_VOTERS: "1@kafka:9093" # 컨트롤러 지정 | ||||||||||||||
|
|
||||||||||||||
| # 리스너 설정 (CONTROLLER 추가 필수) | ||||||||||||||
| KAFKA_LISTENERS: 'PLAINTEXT://0.0.0.0:9092,CONTROLLER://0.0.0.0:9093,PLAINTEXT_HOST://0.0.0.0:29092' | ||||||||||||||
| KAFKA_ADVERTISED_LISTENERS: 'PLAINTEXT://kafka:9092,PLAINTEXT_HOST://localhost:29092' | ||||||||||||||
| KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: 'CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT' | ||||||||||||||
| KAFKA_CONTROLLER_LISTENER_NAMES: 'CONTROLLER' | ||||||||||||||
|
|
||||||||||||||
| # Mac(ARM) 호환 설정 및 성능 최적화 | ||||||||||||||
| _JAVA_OPTIONS: "-XX:UseSVE=0" | ||||||||||||||
| KAFKA_HEAP_OPTS: "-Xms256M -Xmx256M" # JVM 힙 메모리 | ||||||||||||||
|
Comment on lines
+73
to
+75
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: # First, locate and examine the docker-compose.yml file
find . -name "docker-compose.yml" -type fRepository: SeeATheater/CC_Backend Length of output: 116 🏁 Script executed: # Also check the repository structure
git ls-files | head -20Repository: SeeATheater/CC_Backend Length of output: 545 🌐 Web query:
💡 Result: Short answer
References If you want, I can: check which JDK release on your machine contains the OpenJDK fix, or show the exact command to set JAVA_TOOL_OPTIONS permanently. 🏁 Script executed: # Read the docker-compose.yml file to see the context
cat -n docker-compose.yml | head -80Repository: SeeATheater/CC_Backend Length of output: 3006 🏁 Script executed: # Check for existing override files and .env files
ls -la | grep -E "docker-compose|\.env"Repository: SeeATheater/CC_Backend Length of output: 133 🏁 Script executed: # Search for .env files throughout the repo
find . -name ".env*" -o -name "docker-compose.override.yml"Repository: SeeATheater/CC_Backend Length of output: 48 🏁 Script executed: # Check if Dockerfile or build config specifies JDK version to understand if OpenJDK fix is in use
cat Dockerfile | head -30Repository: SeeATheater/CC_Backend Length of output: 264 🏁 Script executed: # Verify the exact context: does x86_64 ignore or reject the flag?
# Check any documentation or comments about Kafka setup
grep -r "UseSVE\|architecture\|ARM\|x86" . --include="*.md" --include="*.txt" 2>/dev/nullRepository: SeeATheater/CC_Backend Length of output: 48 Move
The suggested approach follows the pattern already used by the app services: Example approach- _JAVA_OPTIONS: "-XX:UseSVE=0"
+ _JAVA_OPTIONS: "${KAFKA_JAVA_OPTIONS:-}"Then set 📝 Committable suggestion
Suggested change
🤖 Prompt for AI Agents |
||||||||||||||
| KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1 | ||||||||||||||
| KAFKA_GROUP_INITIAL_REBALANCE_DELAY_MS: 0 | ||||||||||||||
| KAFKA_TRANSACTION_STATE_LOG_MIN_ISR: 1 | ||||||||||||||
| KAFKA_TRANSACTION_STATE_LOG_REPLICATION_FACTOR: 1 | ||||||||||||||
| volumes: | ||||||||||||||
| - kafka_data:/var/lib/kafka/data # <- Docker 내부 볼륨만 사용 | ||||||||||||||
| restart: unless-stopped | ||||||||||||||
|
|
||||||||||||||
| kafka-ui: | ||||||||||||||
| image: provectuslabs/kafka-ui:latest | ||||||||||||||
| container_name: kafka-ui | ||||||||||||||
| ports: | ||||||||||||||
| - "8085:8080" # 호스트 8085로 접속 가능 | ||||||||||||||
| environment: | ||||||||||||||
| KAFKA_CLUSTERS_0_NAME: local | ||||||||||||||
| KAFKA_CLUSTERS_0_BOOTSTRAPSERVERS: kafka:9092 | ||||||||||||||
| KAFKA_CLUSTERS_0_ZOOKEEPER: "" # KRaft 모드라 Zookeeper 필요 없음 | ||||||||||||||
| depends_on: | ||||||||||||||
| - kafka | ||||||||||||||
| restart: unless-stopped | ||||||||||||||
|
|
||||||||||||||
| volumes: | ||||||||||||||
| redis_data: | ||||||||||||||
| driver: local | ||||||||||||||
| kafka_data: | ||||||||||||||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -167,4 +167,5 @@ public void reject(String rejectReason){ | |
| this.rejectReason = rejectReason; | ||
|
|
||
| } | ||
|
|
||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -85,6 +85,7 @@ public enum ErrorStatus implements BaseErrorCode { | |
| AMATEUR_TICKET_NOT_FOUND(HttpStatus.NOT_FOUND, "AMATEURTICKET4000", "존재하지 않는 소극장 공연 티켓입니다."), | ||
| AMATEUR_TICKET_STOCK(HttpStatus.BAD_REQUEST, "AMATEURTICKET4001", "주문 수량은 최소 1개 이상이어야 합니다."), | ||
| AMATEUR_SHOW_MISMATCH(HttpStatus.NOT_FOUND, "AMATEURTICKET4002", "회차와 티켓에 해당하는 공연이 일치하지 않습니다."), | ||
|
|
||
| // PHOTOALBUM ERROR | ||
| PHOTOALBUM_NOT_FOUND(HttpStatus.NOT_FOUND, "PHOTOALBUM4000", "존재하지 않는 사진첩입니다."), | ||
|
|
||
|
|
@@ -108,6 +109,7 @@ public enum ErrorStatus implements BaseErrorCode { | |
|
|
||
| //NOTICE ERROR | ||
| MEMBERNOTICE_NOT_FOUND(HttpStatus.NOT_FOUND, "MEMBERNOTICE4001", "존재하지 않는 알림입니다."), | ||
| NOTICE_NOT_FOUND(HttpStatus.NOT_FOUND, "NOTICE4001", "존재하지 않는 알림입니다."), | ||
|
Comment on lines
110
to
+112
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🧩 Analysis chain🏁 Script executed: cat -n src/main/java/cc/backend/apiPayLoad/code/status/ErrorStatus.java | sed -n '100,120p'Repository: SeeATheater/CC_Backend Length of output: 1396 🏁 Script executed: # Search for usages of these constants
rg "MEMBERNOTICE_NOT_FOUND|NOTICE_NOT_FOUND" -B 2 -A 2Repository: SeeATheater/CC_Backend Length of output: 1303 🏁 Script executed: # Check for any comments or documentation about notice vs membernotice
rg -i "notice" src/main/java/cc/backend/apiPayLoad/code/status/ErrorStatus.java -B 1 -A 1 | head -50Repository: SeeATheater/CC_Backend Length of output: 270 🏁 Script executed: # Search for all usages of NOTICE_NOT_FOUND more broadly
rg "NOTICE_NOT_FOUND" -r "Found in: $FILE"Repository: SeeATheater/CC_Backend Length of output: 498 🏁 Script executed: # Check for Notice service/repository files
fd -t f "Notice" src/main/java --type fRepository: SeeATheater/CC_Backend Length of output: 953 🏁 Script executed: # Look at the structure to find notice-related classes
fd -t d "notice" src/main/javaRepository: SeeATheater/CC_Backend Length of output: 98 🏁 Script executed: # Check NoticeService for how it handles not found cases
cat -n src/main/java/cc/backend/notice/service/NoticeService.javaRepository: SeeATheater/CC_Backend Length of output: 933 🏁 Script executed: # Check NoticeServiceImpl for how it handles not found cases
cat -n src/main/java/cc/backend/notice/service/NoticeServiceImpl.javaRepository: SeeATheater/CC_Backend Length of output: 12662 🏁 Script executed: # Check if there's a controller that might retrieve Notice directly
rg "noticeRepository\.findById|getNotice|Notice.*not.*found" -i -A 2 -B 2Repository: SeeATheater/CC_Backend Length of output: 10769 🏁 Script executed: # Check MemberNoticeController to understand the API patterns
head -100 src/main/java/cc/backend/notice/controller/MemberNoticeController.javaRepository: SeeATheater/CC_Backend Length of output: 2516 Remove unused
🤖 Prompt for AI Agents |
||
| // INQUIRY ERROR | ||
| INQUIRY_NOT_FOUND(HttpStatus.NOT_FOUND, "INQUIRY4000", "존재하지 않는 문의글입니다."), | ||
| FORBIDDEN_INQUIRY_ACCESS(HttpStatus.NOT_FOUND, "INQUIRY4001", "로그인한 멤버가 작성하지 않는 문의글입니다."), | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🧩 Analysis chain
🏁 Script executed:
Repository: SeeATheater/CC_Backend
Length of output: 188
🏁 Script executed:
Repository: SeeATheater/CC_Backend
Length of output: 123
🏁 Script executed:
Repository: SeeATheater/CC_Backend
Length of output: 5816
Add readiness gating for Kafka and define Kafka healthcheck.
depends_ononly enforces start order, not readiness. Without a Kafka healthcheck, the suggestedcondition: service_healthycannot work. The Kafka service (lines 55–83) lacks a healthcheck entirely, and app-blue/app-green (lines 29–32, 50–52) depend on Kafka without gating on readiness. This risks startup failures if the app attempts connections before Kafka is ready.Define a Kafka healthcheck first, then gate the app services on it:
✅ Suggested adjustment
Add to Kafka service:
kafka: image: confluentinc/cp-kafka:latest container_name: kafka ports: - "9092:9092" - "29092:29092" environment: ... + healthcheck: + test: ["CMD-SHELL", "kafka-broker-api-versions.sh --bootstrap-server=localhost:9092 || exit 1"] + interval: 10s + timeout: 5s + retries: 5 + start_period: 30s volumes: - kafka_data:/var/lib/kafka/data restart: unless-stoppedThen update app services:
Apply to both app-blue and app-green.
📝 Committable suggestion
🤖 Prompt for AI Agents