- prediction/: FastAPI 7단계 분류 파이프라인 + 6개 탐지 알고리즘 - snpdb 궤적 조회 → 인메모리 캐시(13K척) → 분류 → kcgdb 저장 - APScheduler 5분 주기, Python 3.9 호환 - 버그 수정: @property last_bucket, SQL INTERVAL 바인딩, rollback, None 가드 - 보안: DB 비밀번호 하드코딩 제거 → env 환경변수 필수 - deploy/kcg-prediction.service: systemd 서비스 (redis-211, 포트 8001) - deploy.yml: prediction CI/CD 배포 단계 추가 (192.168.1.18:32023) - backend: PredictionProxyController (health/status/trigger 프록시) - backend: AppProperties predictionBaseUrl + AuthFilter 인증 예외 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
67 lines
1.7 KiB
Python
67 lines
1.7 KiB
Python
import logging
|
|
import sys
|
|
from contextlib import asynccontextmanager
|
|
|
|
from fastapi import BackgroundTasks, FastAPI
|
|
|
|
from config import settings
|
|
from db import kcgdb, snpdb
|
|
from scheduler import get_last_run, run_analysis_cycle, start_scheduler, stop_scheduler
|
|
|
|
logging.basicConfig(
|
|
level=getattr(logging, settings.LOG_LEVEL, logging.INFO),
|
|
format='%(asctime)s [%(levelname)s] %(name)s: %(message)s',
|
|
stream=sys.stdout,
|
|
)
|
|
logger = logging.getLogger(__name__)
|
|
|
|
|
|
@asynccontextmanager
|
|
async def lifespan(application: FastAPI):
|
|
from cache.vessel_store import vessel_store
|
|
|
|
logger.info('starting KCG Prediction Service')
|
|
snpdb.init_pool()
|
|
kcgdb.init_pool()
|
|
|
|
# 인메모리 캐시 초기 로드 (24시간)
|
|
logger.info('loading initial vessel data (%dh)...', settings.INITIAL_LOAD_HOURS)
|
|
vessel_store.load_initial(settings.INITIAL_LOAD_HOURS)
|
|
logger.info('initial load complete: %s', vessel_store.stats())
|
|
|
|
start_scheduler()
|
|
yield
|
|
stop_scheduler()
|
|
snpdb.close_pool()
|
|
kcgdb.close_pool()
|
|
logger.info('KCG Prediction Service stopped')
|
|
|
|
|
|
app = FastAPI(
|
|
title='KCG Prediction Service',
|
|
version='2.0.0',
|
|
lifespan=lifespan,
|
|
)
|
|
|
|
|
|
@app.get('/health')
|
|
def health_check():
|
|
from cache.vessel_store import vessel_store
|
|
return {
|
|
'status': 'ok',
|
|
'snpdb': snpdb.check_health(),
|
|
'kcgdb': kcgdb.check_health(),
|
|
'store': vessel_store.stats(),
|
|
}
|
|
|
|
|
|
@app.get('/api/v1/analysis/status')
|
|
def analysis_status():
|
|
return get_last_run()
|
|
|
|
|
|
@app.post('/api/v1/analysis/trigger')
|
|
def trigger_analysis(background_tasks: BackgroundTasks):
|
|
background_tasks.add_task(run_analysis_cycle)
|
|
return {'message': 'analysis cycle triggered'}
|