mirror of
https://github.com/ktds-dg0501/kt-event-marketing.git
synced 2026-06-12 23:19:10 +00:00
AI 서비스 Kafka/Redis 통합 테스트 및 설정 개선
- Gradle 빌드 캐시 파일 제외 (.gitignore 업데이트) - Kafka 통합 테스트 구현 (AIJobConsumerIntegrationTest) - 단위 테스트 추가 (Controller, Service 레이어) - IntelliJ 실행 프로파일 자동 생성 도구 추가 - Kafka 테스트 배치 스크립트 추가 - Redis 캐시 설정 개선 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
@echo off
|
||||
REM ============================================
|
||||
REM Kafka/Redis 통합 테스트 스크립트
|
||||
REM ============================================
|
||||
|
||||
echo ============================================
|
||||
echo Kafka/Redis 통합 테스트 시작
|
||||
echo ============================================
|
||||
echo.
|
||||
|
||||
REM 현재 디렉토리 확인
|
||||
cd /d "%~dp0\.."
|
||||
echo 현재 디렉토리: %CD%
|
||||
echo.
|
||||
|
||||
REM 로그 디렉토리 확인 및 생성
|
||||
if not exist "logs" mkdir logs
|
||||
echo 로그 디렉토리: %CD%\logs
|
||||
echo.
|
||||
|
||||
REM 테스트 타임스탬프
|
||||
set TEST_TIMESTAMP=%date:~0,4%%date:~5,2%%date:~8,2%_%time:~0,2%%time:~3,2%%time:~6,2%
|
||||
set TEST_TIMESTAMP=%TEST_TIMESTAMP: =0%
|
||||
set TEST_LOG=logs\kafka-redis-test_%TEST_TIMESTAMP%.log
|
||||
|
||||
echo ============================================
|
||||
echo 1단계: Kafka 수동 테스트 메시지 전송
|
||||
echo ============================================
|
||||
echo.
|
||||
echo Kafka 메시지 전송 중...
|
||||
gradlew ai-service:runKafkaManualTest > %TEST_LOG% 2>&1
|
||||
if %ERRORLEVEL% EQU 0 (
|
||||
echo ✓ Kafka 메시지 전송 완료
|
||||
) else (
|
||||
echo ✗ Kafka 메시지 전송 실패 ^(Error Code: %ERRORLEVEL%^)
|
||||
echo 로그 파일을 확인하세요: %TEST_LOG%
|
||||
)
|
||||
echo.
|
||||
|
||||
echo ============================================
|
||||
echo 2단계: AI 서비스 Consumer 처리 대기
|
||||
echo ============================================
|
||||
echo.
|
||||
echo AI 서비스가 Kafka 메시지를 처리할 때까지 60초 대기...
|
||||
timeout /t 60 /nobreak > nul
|
||||
echo ✓ 대기 완료
|
||||
echo.
|
||||
|
||||
echo ============================================
|
||||
echo 3단계: Job 상태 확인 ^(Redis^)
|
||||
echo ============================================
|
||||
echo.
|
||||
echo Job 상태 조회 중...
|
||||
curl -s "http://localhost:8083/api/v1/ai-service/internal/jobs/manual-job-001/status" >> %TEST_LOG% 2>&1
|
||||
if %ERRORLEVEL% EQU 0 (
|
||||
echo ✓ Job 상태 조회 성공
|
||||
curl -s "http://localhost:8083/api/v1/ai-service/internal/jobs/manual-job-001/status"
|
||||
) else (
|
||||
echo ✗ Job 상태 조회 실패
|
||||
)
|
||||
echo.
|
||||
|
||||
echo ============================================
|
||||
echo 4단계: AI 추천 결과 확인 ^(Redis^)
|
||||
echo ============================================
|
||||
echo.
|
||||
echo AI 추천 결과 조회 중...
|
||||
curl -s "http://localhost:8083/api/v1/ai-service/internal/recommendations/manual-event-001" >> %TEST_LOG% 2>&1
|
||||
if %ERRORLEVEL% EQU 0 (
|
||||
echo ✓ AI 추천 결과 조회 성공
|
||||
curl -s "http://localhost:8083/api/v1/ai-service/internal/recommendations/manual-event-001"
|
||||
) else (
|
||||
echo ✗ AI 추천 결과 조회 실패
|
||||
)
|
||||
echo.
|
||||
|
||||
echo ============================================
|
||||
echo 5단계: 모든 테스트 메시지 상태 확인
|
||||
echo ============================================
|
||||
echo.
|
||||
echo [Job 001] 상태 확인:
|
||||
curl -s "http://localhost:8083/api/v1/ai-service/internal/jobs/manual-job-001/status" | findstr "status"
|
||||
echo.
|
||||
echo [Job 002] 상태 확인:
|
||||
curl -s "http://localhost:8083/api/v1/ai-service/internal/jobs/manual-job-002/status" | findstr "status"
|
||||
echo.
|
||||
echo [Job 003] 상태 확인:
|
||||
curl -s "http://localhost:8083/api/v1/ai-service/internal/jobs/manual-job-003/status" | findstr "status"
|
||||
echo.
|
||||
|
||||
echo ============================================
|
||||
echo 테스트 완료
|
||||
echo ============================================
|
||||
echo.
|
||||
echo 상세 로그 파일: %TEST_LOG%
|
||||
echo.
|
||||
echo 수동 확인 명령어:
|
||||
echo - Job 상태: curl http://localhost:8083/api/v1/ai-service/internal/jobs/{jobId}/status
|
||||
echo - AI 추천: curl http://localhost:8083/api/v1/ai-service/internal/recommendations/{eventId}
|
||||
echo.
|
||||
pause
|
||||
@@ -0,0 +1,37 @@
|
||||
@echo off
|
||||
REM Kafka 수동 테스트 실행 스크립트 (Windows)
|
||||
|
||||
cd /d %~dp0\..
|
||||
|
||||
echo ================================================
|
||||
echo Kafka Manual Test - AI Service
|
||||
echo ================================================
|
||||
echo.
|
||||
echo 이 스크립트는 Kafka에 테스트 메시지를 전송합니다.
|
||||
echo ai-service가 실행 중이어야 메시지를 처리할 수 있습니다.
|
||||
echo.
|
||||
echo Kafka Brokers: 20.249.182.13:9095, 4.217.131.59:9095
|
||||
echo Topic: ai-event-generation-job
|
||||
echo.
|
||||
echo ================================================
|
||||
echo.
|
||||
|
||||
REM 테스트 클래스 실행
|
||||
.\gradlew ai-service:test --tests "com.kt.ai.test.manual.KafkaManualTest" --info
|
||||
|
||||
echo.
|
||||
echo ================================================
|
||||
echo 테스트 완료!
|
||||
echo.
|
||||
echo 결과 확인:
|
||||
echo 1. Job 상태 조회:
|
||||
echo curl http://localhost:8083/api/v1/ai-service/internal/jobs/manual-job-001/status
|
||||
echo.
|
||||
echo 2. AI 추천 결과 조회:
|
||||
echo curl http://localhost:8083/api/v1/ai-service/internal/recommendations/manual-event-001
|
||||
echo.
|
||||
echo 3. Redis 키 확인:
|
||||
echo curl http://localhost:8083/api/v1/ai-service/internal/recommendations/debug/redis-keys
|
||||
echo ================================================
|
||||
|
||||
pause
|
||||
@@ -0,0 +1,303 @@
|
||||
#!/usr/bin/env python3
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
Tripgen Service Runner Script
|
||||
Reads execution profiles from {service-name}/.run/{service-name}.run.xml and runs services accordingly.
|
||||
|
||||
Usage:
|
||||
python run-config.py <service-name>
|
||||
|
||||
Examples:
|
||||
python run-config.py user-service
|
||||
python run-config.py location-service
|
||||
python run-config.py trip-service
|
||||
python run-config.py ai-service
|
||||
"""
|
||||
|
||||
import os
|
||||
import sys
|
||||
import subprocess
|
||||
import xml.etree.ElementTree as ET
|
||||
from pathlib import Path
|
||||
import argparse
|
||||
|
||||
|
||||
def get_project_root():
|
||||
"""Find project root directory"""
|
||||
current_dir = Path(__file__).parent.absolute()
|
||||
while current_dir.parent != current_dir:
|
||||
if (current_dir / 'gradlew').exists() or (current_dir / 'gradlew.bat').exists():
|
||||
return current_dir
|
||||
current_dir = current_dir.parent
|
||||
|
||||
# If gradlew not found, assume parent directory of develop as project root
|
||||
return Path(__file__).parent.parent.absolute()
|
||||
|
||||
|
||||
def parse_run_configurations(project_root, service_name=None):
|
||||
"""Parse run configuration files from .run directories"""
|
||||
configurations = {}
|
||||
|
||||
if service_name:
|
||||
# Parse specific service configuration
|
||||
run_config_path = project_root / service_name / '.run' / f'{service_name}.run.xml'
|
||||
if run_config_path.exists():
|
||||
config = parse_single_run_config(run_config_path, service_name)
|
||||
if config:
|
||||
configurations[service_name] = config
|
||||
else:
|
||||
print(f"[ERROR] Cannot find run configuration: {run_config_path}")
|
||||
else:
|
||||
# Find all service directories
|
||||
service_dirs = ['user-service', 'location-service', 'trip-service', 'ai-service']
|
||||
for service in service_dirs:
|
||||
run_config_path = project_root / service / '.run' / f'{service}.run.xml'
|
||||
if run_config_path.exists():
|
||||
config = parse_single_run_config(run_config_path, service)
|
||||
if config:
|
||||
configurations[service] = config
|
||||
|
||||
return configurations
|
||||
|
||||
|
||||
def parse_single_run_config(config_path, service_name):
|
||||
"""Parse a single run configuration file"""
|
||||
try:
|
||||
tree = ET.parse(config_path)
|
||||
root = tree.getroot()
|
||||
|
||||
# Find configuration element
|
||||
config = root.find('.//configuration[@type="GradleRunConfiguration"]')
|
||||
if config is None:
|
||||
print(f"[WARNING] No Gradle configuration found in {config_path}")
|
||||
return None
|
||||
|
||||
# Extract environment variables
|
||||
env_vars = {}
|
||||
env_option = config.find('.//option[@name="env"]')
|
||||
if env_option is not None:
|
||||
env_map = env_option.find('map')
|
||||
if env_map is not None:
|
||||
for entry in env_map.findall('entry'):
|
||||
key = entry.get('key')
|
||||
value = entry.get('value')
|
||||
if key and value:
|
||||
env_vars[key] = value
|
||||
|
||||
# Extract task names
|
||||
task_names = []
|
||||
task_names_option = config.find('.//option[@name="taskNames"]')
|
||||
if task_names_option is not None:
|
||||
task_list = task_names_option.find('list')
|
||||
if task_list is not None:
|
||||
for option in task_list.findall('option'):
|
||||
value = option.get('value')
|
||||
if value:
|
||||
task_names.append(value)
|
||||
|
||||
if env_vars or task_names:
|
||||
return {
|
||||
'env_vars': env_vars,
|
||||
'task_names': task_names,
|
||||
'config_path': str(config_path)
|
||||
}
|
||||
|
||||
return None
|
||||
|
||||
except ET.ParseError as e:
|
||||
print(f"[ERROR] XML parsing error in {config_path}: {e}")
|
||||
return None
|
||||
except Exception as e:
|
||||
print(f"[ERROR] Error reading {config_path}: {e}")
|
||||
return None
|
||||
|
||||
|
||||
def get_gradle_command(project_root):
|
||||
"""Return appropriate Gradle command for OS"""
|
||||
if os.name == 'nt': # Windows
|
||||
gradle_bat = project_root / 'gradlew.bat'
|
||||
if gradle_bat.exists():
|
||||
return str(gradle_bat)
|
||||
return 'gradle.bat'
|
||||
else: # Unix-like (Linux, macOS)
|
||||
gradle_sh = project_root / 'gradlew'
|
||||
if gradle_sh.exists():
|
||||
return str(gradle_sh)
|
||||
return 'gradle'
|
||||
|
||||
|
||||
def run_service(service_name, config, project_root):
|
||||
"""Run service"""
|
||||
print(f"[START] Starting {service_name} service...")
|
||||
|
||||
# Set environment variables
|
||||
env = os.environ.copy()
|
||||
for key, value in config['env_vars'].items():
|
||||
env[key] = value
|
||||
print(f" [ENV] {key}={value}")
|
||||
|
||||
# Prepare Gradle command
|
||||
gradle_cmd = get_gradle_command(project_root)
|
||||
|
||||
# Execute tasks
|
||||
for task_name in config['task_names']:
|
||||
print(f"\n[RUN] Executing: {task_name}")
|
||||
|
||||
cmd = [gradle_cmd, task_name]
|
||||
|
||||
try:
|
||||
# Execute from project root directory
|
||||
process = subprocess.Popen(
|
||||
cmd,
|
||||
cwd=project_root,
|
||||
env=env,
|
||||
stdout=subprocess.PIPE,
|
||||
stderr=subprocess.STDOUT,
|
||||
universal_newlines=True,
|
||||
bufsize=1,
|
||||
encoding='utf-8',
|
||||
errors='replace'
|
||||
)
|
||||
|
||||
print(f"[CMD] Command: {' '.join(cmd)}")
|
||||
print(f"[DIR] Working directory: {project_root}")
|
||||
print("=" * 50)
|
||||
|
||||
# Real-time output
|
||||
for line in process.stdout:
|
||||
print(line.rstrip())
|
||||
|
||||
# Wait for process completion
|
||||
process.wait()
|
||||
|
||||
if process.returncode == 0:
|
||||
print(f"\n[SUCCESS] {task_name} execution completed")
|
||||
else:
|
||||
print(f"\n[FAILED] {task_name} execution failed (exit code: {process.returncode})")
|
||||
return False
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print(f"\n[STOP] Interrupted by user")
|
||||
process.terminate()
|
||||
return False
|
||||
except Exception as e:
|
||||
print(f"\n[ERROR] Execution error: {e}")
|
||||
return False
|
||||
|
||||
return True
|
||||
|
||||
|
||||
def list_available_services(configurations):
|
||||
"""List available services"""
|
||||
print("[LIST] Available services:")
|
||||
print("=" * 40)
|
||||
|
||||
for service_name, config in configurations.items():
|
||||
if config['task_names']:
|
||||
print(f" [SERVICE] {service_name}")
|
||||
if 'config_path' in config:
|
||||
print(f" +-- Config: {config['config_path']}")
|
||||
for task in config['task_names']:
|
||||
print(f" +-- Task: {task}")
|
||||
print(f" +-- {len(config['env_vars'])} environment variables")
|
||||
print()
|
||||
|
||||
|
||||
def main():
|
||||
"""Main function"""
|
||||
parser = argparse.ArgumentParser(
|
||||
description='Tripgen Service Runner Script',
|
||||
formatter_class=argparse.RawDescriptionHelpFormatter,
|
||||
epilog="""
|
||||
Examples:
|
||||
python run-config.py user-service
|
||||
python run-config.py location-service
|
||||
python run-config.py trip-service
|
||||
python run-config.py ai-service
|
||||
python run-config.py --list
|
||||
"""
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'service_name',
|
||||
nargs='?',
|
||||
help='Service name to run'
|
||||
)
|
||||
|
||||
parser.add_argument(
|
||||
'--list', '-l',
|
||||
action='store_true',
|
||||
help='List available services'
|
||||
)
|
||||
|
||||
args = parser.parse_args()
|
||||
|
||||
# Find project root
|
||||
project_root = get_project_root()
|
||||
print(f"[INFO] Project root: {project_root}")
|
||||
|
||||
# Parse run configurations
|
||||
print("[INFO] Reading run configuration files...")
|
||||
configurations = parse_run_configurations(project_root)
|
||||
|
||||
if not configurations:
|
||||
print("[ERROR] No execution configurations found")
|
||||
return 1
|
||||
|
||||
print(f"[INFO] Found {len(configurations)} execution configurations")
|
||||
|
||||
# List services request
|
||||
if args.list:
|
||||
list_available_services(configurations)
|
||||
return 0
|
||||
|
||||
# If service name not provided
|
||||
if not args.service_name:
|
||||
print("\n[ERROR] Please provide service name")
|
||||
list_available_services(configurations)
|
||||
print("Usage: python run-config.py <service-name>")
|
||||
return 1
|
||||
|
||||
# Find service
|
||||
service_name = args.service_name
|
||||
|
||||
# Try to parse specific service configuration if not found
|
||||
if service_name not in configurations:
|
||||
print(f"[INFO] Trying to find configuration for '{service_name}'...")
|
||||
configurations = parse_run_configurations(project_root, service_name)
|
||||
|
||||
if service_name not in configurations:
|
||||
print(f"[ERROR] Cannot find '{service_name}' service")
|
||||
list_available_services(configurations)
|
||||
return 1
|
||||
|
||||
config = configurations[service_name]
|
||||
|
||||
if not config['task_names']:
|
||||
print(f"[ERROR] No executable tasks found for '{service_name}' service")
|
||||
return 1
|
||||
|
||||
# Execute service
|
||||
print(f"\n[TARGET] Starting '{service_name}' service execution")
|
||||
print("=" * 50)
|
||||
|
||||
success = run_service(service_name, config, project_root)
|
||||
|
||||
if success:
|
||||
print(f"\n[COMPLETE] '{service_name}' service started successfully!")
|
||||
return 0
|
||||
else:
|
||||
print(f"\n[FAILED] Failed to start '{service_name}' service")
|
||||
return 1
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
try:
|
||||
exit_code = main()
|
||||
sys.exit(exit_code)
|
||||
except KeyboardInterrupt:
|
||||
print("\n[STOP] Interrupted by user")
|
||||
sys.exit(1)
|
||||
except Exception as e:
|
||||
print(f"\n[ERROR] Unexpected error occurred: {e}")
|
||||
sys.exit(1)
|
||||
Reference in New Issue
Block a user