상태 JSON 파일의 요청 통계 및 가동 시간을 업데이트하고, 새로운 모델 정보 API를 추가하였습니다. 모니터링 포트를 8080에서 8888로 변경하였으며, .gitignore 파일에 로그 파일 패턴을 추가하였습니다. 스크립트에서 가상환경 경로 자동 감지 기능을 개선하였습니다.
This commit is contained in:
parent
0cb1596be1
commit
29f0de65e1
|
|
@ -1,3 +1,4 @@
|
|||
logs/
|
||||
bin/
|
||||
include/
|
||||
lib/
|
||||
|
|
@ -17,6 +18,7 @@ pyvenv.cfg
|
|||
*.pyzw
|
||||
*.pyzwz
|
||||
*.pyzwzw
|
||||
logs/
|
||||
status.json
|
||||
|
||||
*.logs
|
||||
*.log
|
||||
*.pid
|
||||
|
|
@ -352,6 +352,47 @@ async def remove_background(
|
|||
|
||||
|
||||
|
||||
@router.get("/api/v1/model")
|
||||
async def get_model_info():
|
||||
"""모델 정보 반환 (클라이언트 헬스체크 호환)"""
|
||||
try:
|
||||
# 현재 사용 가능한 모델 목록
|
||||
models = [
|
||||
{
|
||||
"name": "simple-lama",
|
||||
"type": "inpainting",
|
||||
"status": "available",
|
||||
"description": "Simple LAMA 인페인팅 모델"
|
||||
},
|
||||
{
|
||||
"name": "migan",
|
||||
"type": "inpainting",
|
||||
"status": "available",
|
||||
"description": "MIGAN 인페인팅 모델"
|
||||
},
|
||||
{
|
||||
"name": "rembg",
|
||||
"type": "rembg",
|
||||
"status": "available",
|
||||
"description": "Rembg 배경 제거 모델"
|
||||
}
|
||||
]
|
||||
|
||||
return {
|
||||
"success": True,
|
||||
"models": models,
|
||||
"server_status": "running",
|
||||
"version": "1.0.0",
|
||||
"device": "cuda" if settings.IS_JETSON else "cuda",
|
||||
"is_jetson": settings.IS_JETSON,
|
||||
"timestamp": datetime.now().isoformat()
|
||||
}
|
||||
|
||||
except Exception as e:
|
||||
logger.error(f"모델 정보 조회 실패: {e}")
|
||||
raise HTTPException(status_code=500, detail=f"모델 정보 조회 실패: {str(e)}")
|
||||
|
||||
|
||||
@router.get("/api/v1/samplers")
|
||||
async def get_samplers():
|
||||
"""사용 가능한 샘플러 목록 반환 (iopaint 호환)"""
|
||||
|
|
|
|||
|
|
@ -54,7 +54,7 @@ class Settings(BaseSettings):
|
|||
|
||||
# Monitoring
|
||||
ENABLE_MONITORING: bool = True
|
||||
MONITORING_PORT: int = 8080
|
||||
MONITORING_PORT: int = 8888
|
||||
|
||||
# Jetson performance settings
|
||||
JETSON_GPU_FREQ: int = 1200 # MHz
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ from fastapi.staticfiles import StaticFiles
|
|||
from fastapi.responses import HTMLResponse
|
||||
import uvicorn
|
||||
from fastapi import APIRouter, Request
|
||||
import websockets.exceptions
|
||||
|
||||
from ..core.worker_manager import worker_manager
|
||||
from ..core.session_pool import session_pool
|
||||
|
|
@ -571,6 +572,50 @@ HTML_TEMPLATE = """
|
|||
font-size: 0.9em;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.status {
|
||||
padding: 2px 8px;
|
||||
border-radius: 4px;
|
||||
font-weight: bold;
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.status.connected {
|
||||
background-color: #d4edda;
|
||||
color: #155724;
|
||||
}
|
||||
|
||||
.status.connecting {
|
||||
background-color: #fff3cd;
|
||||
color: #856404;
|
||||
}
|
||||
|
||||
.status.reconnecting {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
animation: pulse 1s infinite;
|
||||
}
|
||||
|
||||
.status.disconnected {
|
||||
background-color: #f8d7da;
|
||||
color: #721c24;
|
||||
}
|
||||
|
||||
.status.error {
|
||||
background-color: #f5c6cb;
|
||||
color: #491217;
|
||||
}
|
||||
|
||||
.status.failed {
|
||||
background-color: #d1ecf1;
|
||||
color: #0c5460;
|
||||
}
|
||||
|
||||
@keyframes pulse {
|
||||
0% { opacity: 1; }
|
||||
50% { opacity: 0.5; }
|
||||
100% { opacity: 1; }
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
|
|
@ -793,7 +838,8 @@ HTML_TEMPLATE = """
|
|||
</div>
|
||||
|
||||
<div class="refresh-time">
|
||||
마지막 업데이트: <span id="last-update">-</span>
|
||||
마지막 업데이트: <span id="last-update">-</span> |
|
||||
연결 상태: <span id="connection-status" class="status connecting">연결 중...</span>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
@ -852,20 +898,100 @@ HTML_TEMPLATE = """
|
|||
}
|
||||
});
|
||||
|
||||
// WebSocket 연결
|
||||
const ws = new WebSocket(`ws://${window.location.host}/ws`);
|
||||
// WebSocket 연결 관리
|
||||
let ws;
|
||||
let reconnectAttempts = 0;
|
||||
const maxReconnectAttempts = 5;
|
||||
const reconnectInterval = 3000; // 3초
|
||||
let lastHeartbeat = Date.now();
|
||||
const heartbeatTimeout = 10000; // 10초 타임아웃
|
||||
|
||||
ws.onmessage = function(event) {
|
||||
const data = JSON.parse(event.data);
|
||||
updateDashboard(data);
|
||||
};
|
||||
function connectWebSocket() {
|
||||
try {
|
||||
ws = new WebSocket(`ws://${window.location.host}/ws`);
|
||||
|
||||
ws.onopen = function() {
|
||||
console.log('WebSocket 연결이 성공했습니다.');
|
||||
reconnectAttempts = 0;
|
||||
// 연결 상태 표시 업데이트
|
||||
document.getElementById('connection-status').textContent = '연결됨';
|
||||
document.getElementById('connection-status').className = 'status connected';
|
||||
};
|
||||
|
||||
ws.onmessage = function(event) {
|
||||
try {
|
||||
const data = JSON.parse(event.data);
|
||||
|
||||
// heartbeat 체크
|
||||
if (data.heartbeat) {
|
||||
lastHeartbeat = Date.now();
|
||||
}
|
||||
|
||||
updateDashboard(data);
|
||||
} catch (e) {
|
||||
console.error('데이터 파싱 오류:', e);
|
||||
}
|
||||
};
|
||||
|
||||
ws.onclose = function(event) {
|
||||
console.log(`WebSocket 연결이 종료되었습니다. 코드: ${event.code}, 이유: ${event.reason}`);
|
||||
document.getElementById('connection-status').textContent = '연결 끊어짐';
|
||||
document.getElementById('connection-status').className = 'status disconnected';
|
||||
|
||||
// 자동 재연결 시도
|
||||
if (reconnectAttempts < maxReconnectAttempts) {
|
||||
reconnectAttempts++;
|
||||
console.log(`재연결 시도 ${reconnectAttempts}/${maxReconnectAttempts} in ${reconnectInterval/1000}초...`);
|
||||
document.getElementById('connection-status').textContent = `재연결 중... (${reconnectAttempts}/${maxReconnectAttempts})`;
|
||||
document.getElementById('connection-status').className = 'status reconnecting';
|
||||
|
||||
setTimeout(connectWebSocket, reconnectInterval);
|
||||
} else {
|
||||
console.log('최대 재연결 시도 횟수를 초과했습니다. 페이지를 새로고침합니다.');
|
||||
document.getElementById('connection-status').textContent = '연결 실패';
|
||||
document.getElementById('connection-status').className = 'status failed';
|
||||
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 5000);
|
||||
}
|
||||
};
|
||||
|
||||
ws.onerror = function(error) {
|
||||
console.error('WebSocket 오류:', error);
|
||||
document.getElementById('connection-status').textContent = '연결 오류';
|
||||
document.getElementById('connection-status').className = 'status error';
|
||||
};
|
||||
|
||||
} catch (error) {
|
||||
console.error('WebSocket 연결 생성 오류:', error);
|
||||
document.getElementById('connection-status').textContent = '연결 생성 실패';
|
||||
document.getElementById('connection-status').className = 'status error';
|
||||
}
|
||||
}
|
||||
|
||||
ws.onclose = function() {
|
||||
console.log('WebSocket 연결이 종료되었습니다.');
|
||||
setTimeout(() => {
|
||||
location.reload();
|
||||
}, 5000);
|
||||
};
|
||||
// 페이지 가시성 변경 감지
|
||||
document.addEventListener('visibilitychange', function() {
|
||||
if (document.visibilityState === 'visible') {
|
||||
// 탭이 다시 활성화되면 연결 상태 확인
|
||||
if (ws.readyState !== WebSocket.OPEN) {
|
||||
console.log('탭이 활성화되어 WebSocket 재연결을 시도합니다.');
|
||||
connectWebSocket();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// 초기 연결
|
||||
connectWebSocket();
|
||||
|
||||
// heartbeat 모니터링
|
||||
setInterval(function() {
|
||||
const now = Date.now();
|
||||
if (now - lastHeartbeat > heartbeatTimeout && ws && ws.readyState === WebSocket.OPEN) {
|
||||
console.log('heartbeat 타임아웃 - 연결을 다시 시도합니다.');
|
||||
ws.close();
|
||||
}
|
||||
}, 5000); // 5초마다 체크
|
||||
|
||||
function updateDashboard(data) {
|
||||
console.log("받은 데이터:", data); // 디버깅용 로그 추가
|
||||
|
|
@ -1199,17 +1325,39 @@ async def websocket_endpoint(websocket: WebSocket):
|
|||
"""WebSocket 연결을 처리합니다."""
|
||||
await websocket.accept()
|
||||
connected_clients.append(websocket)
|
||||
logger.info(f"WebSocket 클라이언트 연결됨: {websocket.client}")
|
||||
|
||||
try:
|
||||
while True:
|
||||
# 주기적으로 데이터 전송
|
||||
data = await monitoring_data.collect_data()
|
||||
await websocket.send_json(data)
|
||||
|
||||
# heartbeat 메시지 추가
|
||||
data['heartbeat'] = time.time()
|
||||
data['server_status'] = 'running'
|
||||
|
||||
try:
|
||||
await websocket.send_json(data)
|
||||
except (websockets.exceptions.ConnectionClosedOK,
|
||||
websockets.exceptions.ConnectionClosedError,
|
||||
RuntimeError) as e:
|
||||
logger.info(f"WebSocket 연결이 끊어짐: {e}")
|
||||
break
|
||||
except Exception as e:
|
||||
logger.error(f"데이터 전송 오류: {e}")
|
||||
break
|
||||
|
||||
await asyncio.sleep(2) # 2초마다 업데이트
|
||||
|
||||
except WebSocketDisconnect:
|
||||
connected_clients.remove(websocket)
|
||||
logger.info("클라이언트 연결 해제")
|
||||
logger.info("클라이언트가 연결을 끊음")
|
||||
except Exception as e:
|
||||
logger.error(f"WebSocket 오류: {e}")
|
||||
finally:
|
||||
# 연결된 클라이언트 목록에서 제거
|
||||
if websocket in connected_clients:
|
||||
connected_clients.remove(websocket)
|
||||
logger.info(f"WebSocket 클라이언트 연결 해제됨: {websocket.client}")
|
||||
|
||||
|
||||
async def broadcast_data():
|
||||
|
|
@ -1225,7 +1373,11 @@ async def broadcast_data():
|
|||
for client in connected_clients:
|
||||
try:
|
||||
await client.send_text(message)
|
||||
except Exception:
|
||||
except (websockets.exceptions.ConnectionClosedOK,
|
||||
websockets.exceptions.ConnectionClosedError,
|
||||
RuntimeError,
|
||||
Exception) as e:
|
||||
logger.debug(f"브로드캐스트 중 클라이언트 연결 끊어짐: {e}")
|
||||
disconnected.append(client)
|
||||
|
||||
for client in disconnected:
|
||||
|
|
|
|||
1729
logs/main_server.log
1729
logs/main_server.log
File diff suppressed because it is too large
Load Diff
|
|
@ -1 +1 @@
|
|||
1312285
|
||||
1328887
|
||||
|
|
|
|||
|
|
@ -1,10 +1,6 @@
|
|||
INFO: Started server process [1312316]
|
||||
INFO: Started server process [1328918]
|
||||
INFO: Waiting for application startup.
|
||||
Fan control not available
|
||||
INFO: Application startup complete.
|
||||
INFO: Uvicorn running on http://0.0.0.0:8080 (Press CTRL+C to quit)
|
||||
INFO: 127.0.0.1:35348 - "GET /api/simple HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:37590 - "GET / HTTP/1.1" 200 OK
|
||||
INFO: 127.0.0.1:37590 - "GET /favicon.ico HTTP/1.1" 404 Not Found
|
||||
INFO: ('127.0.0.1', 37632) - "WebSocket /ws" [accepted]
|
||||
INFO: connection open
|
||||
INFO: Uvicorn running on http://0.0.0.0:8888 (Press CTRL+C to quit)
|
||||
INFO: 127.0.0.1:42340 - "GET /api/simple HTTP/1.1" 200 OK
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
1312316
|
||||
1328918
|
||||
|
|
|
|||
|
|
@ -30,9 +30,44 @@ log_error() {
|
|||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# 기본 설정
|
||||
PROJECT_ROOT="/home/ckh08045/work/inpaintServer"
|
||||
VENV_PATH="$PROJECT_ROOT"
|
||||
# 기본 설정 - 동적 경로 처리
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
|
||||
# 가상환경 경로 자동 감지
|
||||
detect_venv_path() {
|
||||
local possible_paths=(
|
||||
"$PROJECT_ROOT/venv" # 일반적인 venv 경로
|
||||
"$PROJECT_ROOT/.venv" # 숨김 venv 경로
|
||||
"$PROJECT_ROOT/env" # env 경로
|
||||
"$PROJECT_ROOT/.env" # 숨김 env 경로
|
||||
"$PROJECT_ROOT" # 프로젝트 루트 (Jetson 방식)
|
||||
)
|
||||
|
||||
for path in "${possible_paths[@]}"; do
|
||||
if [ -f "$path/bin/python" ] || [ -f "$path/bin/python3" ]; then
|
||||
VENV_PATH="$path"
|
||||
log_info "가상환경 경로 감지: $VENV_PATH"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
# 현재 활성화된 가상환경 확인
|
||||
if [ -n "$VIRTUAL_ENV" ]; then
|
||||
VENV_PATH="$VIRTUAL_ENV"
|
||||
log_info "활성화된 가상환경 사용: $VENV_PATH"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 가상환경을 찾지 못한 경우 시스템별 기본값 사용
|
||||
if [ "$(uname -m)" = "aarch64" ] && uname -a | grep -q "tegra"; then
|
||||
VENV_PATH="$PROJECT_ROOT"
|
||||
log_warning "가상환경을 찾을 수 없어 Jetson 기본값 사용: $VENV_PATH"
|
||||
else
|
||||
VENV_PATH="$PROJECT_ROOT/venv"
|
||||
log_warning "가상환경을 찾을 수 없어 x86 기본값 사용: $VENV_PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
# 시스템 감지
|
||||
detect_system() {
|
||||
|
|
@ -687,6 +722,7 @@ main() {
|
|||
log_info "인페인팅 서버 의존성 설치 시작"
|
||||
|
||||
detect_system
|
||||
detect_venv_path
|
||||
check_system_requirements
|
||||
check_cuda_installation
|
||||
activate_venv
|
||||
|
|
|
|||
|
|
@ -176,8 +176,14 @@ install_dependencies() {
|
|||
fi
|
||||
|
||||
# requirements.txt 확인
|
||||
if [ ! -f "requirements.txt" ]; then
|
||||
log_error "requirements.txt 파일을 찾을 수 없습니다"
|
||||
if [ "$SYSTEM_TYPE" = "x86" ]; then
|
||||
REQ_FILE="requirements_x86.txt"
|
||||
else
|
||||
REQ_FILE="requirements.txt"
|
||||
fi
|
||||
|
||||
if [ ! -f "$REQ_FILE" ]; then
|
||||
log_error "$REQ_FILE 파일을 찾을 수 없습니다"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
|
@ -188,7 +194,7 @@ install_dependencies() {
|
|||
fi
|
||||
|
||||
# 기본 패키지 설치
|
||||
pip install -r requirements.txt
|
||||
pip install -r "$REQ_FILE"
|
||||
|
||||
log_success "의존성 설치 완료"
|
||||
}
|
||||
|
|
@ -282,7 +288,7 @@ print_completion_info() {
|
|||
echo "🚀 서버 접속 정보:"
|
||||
echo " - 메인 API 서버: http://localhost:8008"
|
||||
echo " - API 문서: http://localhost:8008/docs"
|
||||
echo " - 모니터링 대시보드: http://localhost:8080"
|
||||
echo " - 모니터링 대시보드: http://localhost:8888"
|
||||
echo " - 헬스 체크: http://localhost:8008/health"
|
||||
else
|
||||
echo ""
|
||||
|
|
|
|||
|
|
@ -141,7 +141,7 @@ echo " bash scripts/setup_and_run.sh"
|
|||
echo ""
|
||||
log_info "서버 포트:"
|
||||
echo " 메인 서버: http://localhost:8008"
|
||||
echo " 모니터링: http://localhost:8080"
|
||||
echo " 모니터링: http://localhost:8888"
|
||||
echo ""
|
||||
log_info "GPU 설정:"
|
||||
echo " RTX 3060 12GB 권장 설정이 자동으로 적용됩니다"
|
||||
|
|
|
|||
|
|
@ -30,13 +30,48 @@ log_error() {
|
|||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# 기본 설정
|
||||
PROJECT_ROOT="/home/ckh08045/work/inpaintServer"
|
||||
VENV_PATH="$PROJECT_ROOT"
|
||||
# 기본 설정 - 동적 경로 처리
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
MAIN_SERVER_PORT=8008
|
||||
MONITORING_PORT=8080
|
||||
MONITORING_PORT=8888
|
||||
LOG_DIR="$PROJECT_ROOT/logs"
|
||||
|
||||
# 가상환경 경로 자동 감지
|
||||
detect_venv_path() {
|
||||
local possible_paths=(
|
||||
"$PROJECT_ROOT/venv" # 일반적인 venv 경로
|
||||
"$PROJECT_ROOT/.venv" # 숨김 venv 경로
|
||||
"$PROJECT_ROOT/env" # env 경로
|
||||
"$PROJECT_ROOT/.env" # 숨김 env 경로
|
||||
"$PROJECT_ROOT" # 프로젝트 루트 (Jetson 방식)
|
||||
)
|
||||
|
||||
for path in "${possible_paths[@]}"; do
|
||||
if [ -f "$path/bin/python" ] || [ -f "$path/bin/python3" ]; then
|
||||
VENV_PATH="$path"
|
||||
log_info "가상환경 경로 감지: $VENV_PATH"
|
||||
return 0
|
||||
fi
|
||||
done
|
||||
|
||||
# 현재 활성화된 가상환경 확인
|
||||
if [ -n "$VIRTUAL_ENV" ]; then
|
||||
VENV_PATH="$VIRTUAL_ENV"
|
||||
log_info "활성화된 가상환경 사용: $VENV_PATH"
|
||||
return 0
|
||||
fi
|
||||
|
||||
# 가상환경을 찾지 못한 경우 시스템별 기본값 사용
|
||||
if [ "$(uname -m)" = "aarch64" ] && uname -a | grep -q "tegra"; then
|
||||
VENV_PATH="$PROJECT_ROOT"
|
||||
log_warning "가상환경을 찾을 수 없어 Jetson 기본값 사용: $VENV_PATH"
|
||||
else
|
||||
VENV_PATH="$PROJECT_ROOT/venv"
|
||||
log_warning "가상환경을 찾을 수 없어 x86 기본값 사용: $VENV_PATH"
|
||||
fi
|
||||
}
|
||||
|
||||
# 시스템 감지
|
||||
detect_system() {
|
||||
if [ "$(uname -m)" = "aarch64" ] && uname -a | grep -q "tegra"; then
|
||||
|
|
@ -129,6 +164,7 @@ check_environment() {
|
|||
fi
|
||||
|
||||
# 가상환경 확인
|
||||
log_info "가상환경 경로 확인: $VENV_PATH"
|
||||
if [ ! -f "$VENV_PATH/bin/activate" ]; then
|
||||
log_error "가상환경을 찾을 수 없습니다: $VENV_PATH"
|
||||
exit 1
|
||||
|
|
@ -506,6 +542,7 @@ main() {
|
|||
log_info "인페인팅 서버 시작 스크립트 실행"
|
||||
|
||||
detect_system
|
||||
detect_venv_path
|
||||
check_environment
|
||||
activate_venv
|
||||
check_ports
|
||||
|
|
|
|||
|
|
@ -30,11 +30,12 @@ log_error() {
|
|||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# 기본 설정
|
||||
PROJECT_ROOT="/home/ckh08045/work/inpaintServer"
|
||||
# 기본 설정 - 동적 경로 처리
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
LOG_DIR="$PROJECT_ROOT/logs"
|
||||
MAIN_PORT=8008
|
||||
MONITORING_PORT=8080
|
||||
MONITORING_PORT=8888
|
||||
|
||||
# 옵션 파싱
|
||||
DETAILED=false
|
||||
|
|
|
|||
|
|
@ -29,8 +29,9 @@ log_error() {
|
|||
echo -e "${RED}[ERROR]${NC} $1"
|
||||
}
|
||||
|
||||
# 기본 설정
|
||||
PROJECT_ROOT="/home/ckh08045/work/inpaintServer"
|
||||
# 기본 설정 - 동적 경로 처리
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
PROJECT_ROOT="$(dirname "$SCRIPT_DIR")"
|
||||
PID_FILE="$PROJECT_ROOT/server.pid"
|
||||
LOG_FILE="$PROJECT_ROOT/logs/server.log"
|
||||
|
||||
|
|
@ -70,8 +71,8 @@ find_server_processes() {
|
|||
done
|
||||
fi
|
||||
|
||||
# 포트 8080에서 실행 중인 프로세스 찾기 (모니터링)
|
||||
local monitor_processes=$(lsof -ti:8080 2>/dev/null || echo "")
|
||||
# 포트 8888에서 실행 중인 프로세스 찾기 (모니터링)
|
||||
local monitor_processes=$(lsof -ti:8888 2>/dev/null || echo "")
|
||||
if [ -n "$monitor_processes" ]; then
|
||||
for pid in $monitor_processes; do
|
||||
if [[ ! " ${processes[@]} " =~ " ${pid} " ]]; then
|
||||
|
|
@ -135,10 +136,10 @@ stop_server() {
|
|||
log_success "포트 8008 해제됨"
|
||||
fi
|
||||
|
||||
if lsof -ti:8080 > /dev/null 2>&1; then
|
||||
log_warning "포트 8080이 여전히 사용 중입니다"
|
||||
if lsof -ti:8888 > /dev/null 2>&1; then
|
||||
log_warning "포트 8888이 여전히 사용 중입니다"
|
||||
else
|
||||
log_success "포트 8080 해제됨"
|
||||
log_success "포트 8888 해제됨"
|
||||
fi
|
||||
|
||||
log_success "서버 정지 완료"
|
||||
|
|
@ -165,10 +166,10 @@ force_stop() {
|
|||
kill -KILL $port_8008 2>/dev/null || true
|
||||
fi
|
||||
|
||||
local port_8080=$(lsof -ti:8080 2>/dev/null || echo "")
|
||||
if [ -n "$port_8080" ]; then
|
||||
log_info "포트 8080 사용 프로세스 강제 종료 중..."
|
||||
kill -KILL $port_8080 2>/dev/null || true
|
||||
local port_8888=$(lsof -ti:8888 2>/dev/null || echo "")
|
||||
if [ -n "$port_8888" ]; then
|
||||
log_info "포트 8888 사용 프로세스 강제 종료 중..."
|
||||
kill -KILL $port_8888 2>/dev/null || true
|
||||
fi
|
||||
|
||||
# PID 파일 정리
|
||||
|
|
@ -204,10 +205,10 @@ check_status() {
|
|||
log_info "포트 8008: 사용 안함"
|
||||
fi
|
||||
|
||||
if lsof -ti:8080 > /dev/null 2>&1; then
|
||||
log_info "포트 8080: 사용 중 (모니터링 대시보드)"
|
||||
if lsof -ti:8888 > /dev/null 2>&1; then
|
||||
log_info "포트 8888: 사용 중 (모니터링 대시보드)"
|
||||
else
|
||||
log_info "포트 8080: 사용 안함"
|
||||
log_info "포트 8888: 사용 안함"
|
||||
fi
|
||||
}
|
||||
|
||||
|
|
|
|||
64
status.json
64
status.json
|
|
@ -6,7 +6,7 @@
|
|||
"workers_by_status": {
|
||||
"idle": [
|
||||
{
|
||||
"id": "worker_8aca7695",
|
||||
"id": "worker_f42e10e1",
|
||||
"status": "idle",
|
||||
"task_count": 0,
|
||||
"error_count": 0,
|
||||
|
|
@ -37,62 +37,38 @@
|
|||
}
|
||||
},
|
||||
"api_stats": {
|
||||
"total_requests": 7,
|
||||
"successful_requests": 6,
|
||||
"failed_requests": 1,
|
||||
"success_rate": 85.71428571428571,
|
||||
"total_requests": 4,
|
||||
"successful_requests": 4,
|
||||
"failed_requests": 0,
|
||||
"success_rate": 100.0,
|
||||
"endpoint_usage": {
|
||||
"GET /health": 1,
|
||||
"GET /": 1,
|
||||
"GET /favicon.ico": 1,
|
||||
"GET /docs": 2,
|
||||
"GET /openapi.json": 2
|
||||
"GET /health": 2,
|
||||
"GET /api/v1/model": 2
|
||||
},
|
||||
"endpoint_stats": {
|
||||
"GET /health": {
|
||||
"count": 1,
|
||||
"avg_time": 0.0018818378448486328,
|
||||
"min_time": 0.0018818378448486328,
|
||||
"max_time": 0.0018818378448486328,
|
||||
"current_concurrent": 0
|
||||
},
|
||||
"GET /": {
|
||||
"count": 1,
|
||||
"avg_time": 0.0030472278594970703,
|
||||
"min_time": 0.0030472278594970703,
|
||||
"max_time": 0.0030472278594970703,
|
||||
"current_concurrent": 0
|
||||
},
|
||||
"GET /favicon.ico": {
|
||||
"count": 1,
|
||||
"avg_time": 0.002054452896118164,
|
||||
"min_time": 0.002054452896118164,
|
||||
"max_time": 0.002054452896118164,
|
||||
"current_concurrent": 0
|
||||
},
|
||||
"GET /docs": {
|
||||
"count": 2,
|
||||
"avg_time": 0.003388047218322754,
|
||||
"min_time": 0.0019888877868652344,
|
||||
"max_time": 0.0047872066497802734,
|
||||
"avg_time": 0.001588582992553711,
|
||||
"min_time": 0.0013887882232666016,
|
||||
"max_time": 0.0017883777618408203,
|
||||
"current_concurrent": 0
|
||||
},
|
||||
"GET /openapi.json": {
|
||||
"GET /api/v1/model": {
|
||||
"count": 2,
|
||||
"avg_time": 0.02791738510131836,
|
||||
"min_time": 0.002294301986694336,
|
||||
"max_time": 0.05354046821594238,
|
||||
"avg_time": 0.0014955997467041016,
|
||||
"min_time": 0.0014739036560058594,
|
||||
"max_time": 0.0015172958374023438,
|
||||
"current_concurrent": 0
|
||||
}
|
||||
},
|
||||
"average_response_time": 0.009942054748535156,
|
||||
"min_response_time": 0.0018818378448486328,
|
||||
"max_response_time": 0.05354046821594238,
|
||||
"average_response_time": 0.0015420913696289062,
|
||||
"min_response_time": 0.0013887882232666016,
|
||||
"max_response_time": 0.0017883777618408203,
|
||||
"current_concurrent": 0,
|
||||
"max_concurrent": 1,
|
||||
"requests_per_second": 0.004146781630742803,
|
||||
"uptime": 1688.056093454361,
|
||||
"requests_per_second": 0.018707118250962246,
|
||||
"uptime": 213.82235074043274,
|
||||
"recent_errors": []
|
||||
},
|
||||
"timestamp": 1756394399.330041
|
||||
"timestamp": 1756399332.7971911
|
||||
}
|
||||
Loading…
Reference in New Issue