260710_1
This commit is contained in:
@@ -0,0 +1,23 @@
|
||||
-- =============================================================================
|
||||
-- 워크플로우 단계별 상태 관리 테이블
|
||||
-- DBMS: MariaDB 10.6+
|
||||
-- =============================================================================
|
||||
|
||||
USE aislo_db;
|
||||
|
||||
CREATE TABLE IF NOT EXISTS project_workflow_stages (
|
||||
id INT AUTO_INCREMENT PRIMARY KEY,
|
||||
project_id CHAR(36) NOT NULL,
|
||||
stage_no TINYINT NOT NULL, -- 0=파일입력, 1=WF1 ... 6=WF6
|
||||
stage_key VARCHAR(30) NOT NULL, -- 'FILE_INPUT','WF1_SURFACE',...,'WF6_ESTIMATION'
|
||||
state ENUM('NOT_STARTED','IN_PROGRESS','COMPLETE','FAILED','STALE') NOT NULL DEFAULT 'NOT_STARTED',
|
||||
progress_percent TINYINT NOT NULL DEFAULT 0,
|
||||
params JSON NULL, -- 해당 단계에서 사용자가 선택/입력한 값 (재실행 시 재사용)
|
||||
message VARCHAR(255) NULL, -- 진행/오류 메시지
|
||||
started_at TIMESTAMP NULL,
|
||||
completed_at TIMESTAMP NULL,
|
||||
updated_at TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
|
||||
UNIQUE KEY uq_project_stage (project_id, stage_no),
|
||||
INDEX idx_pws_project (project_id),
|
||||
CONSTRAINT fk_pws_project_id FOREIGN KEY (project_id) REFERENCES projects(id) ON DELETE CASCADE
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci;
|
||||
@@ -0,0 +1,158 @@
|
||||
"""워크플로우 단계별 상태 테이블 생성 및 기존 프로젝트 백필 마이그레이션 스크립트."""
|
||||
|
||||
import asyncio
|
||||
import sys
|
||||
from pathlib import Path
|
||||
|
||||
import aiomysql
|
||||
|
||||
# Import DB config
|
||||
sys.path.append(str(Path(__file__).parent.parent))
|
||||
from common_util.common_util_workflow_state import STAGE_KEYS
|
||||
from config.config_db import DB_HOST, DB_NAME, DB_PASSWORD, DB_PORT, DB_USER
|
||||
|
||||
|
||||
async def migrate():
|
||||
print("Database connecting...")
|
||||
connection = await aiomysql.connect(
|
||||
host=DB_HOST,
|
||||
port=DB_PORT,
|
||||
user=DB_USER,
|
||||
password=DB_PASSWORD,
|
||||
db=DB_NAME,
|
||||
charset="utf8mb4",
|
||||
)
|
||||
|
||||
try:
|
||||
async with connection.cursor() as cursor:
|
||||
# 1. 테이블 생성
|
||||
sql_file = Path(__file__).parent / "006_workflow_state.sql"
|
||||
print(f"Executing schema from {sql_file.name}...")
|
||||
sql_content = sql_file.read_text(encoding="utf-8")
|
||||
# Remove USE aislo_db; to avoid issues if any, but splitting is fine
|
||||
statements = [stmt.strip() for stmt in sql_content.split(";") if stmt.strip()]
|
||||
for stmt in statements:
|
||||
await cursor.execute(stmt)
|
||||
print("Table project_workflow_stages created successfully.")
|
||||
|
||||
await connection.commit()
|
||||
|
||||
# 2. 기존 프로젝트 백필
|
||||
async with connection.cursor(aiomysql.DictCursor) as cursor:
|
||||
await cursor.execute("SELECT id, status FROM projects")
|
||||
projects = await cursor.fetchall()
|
||||
print(f"Found {len(projects)} existing projects to backfill.")
|
||||
|
||||
for proj in projects:
|
||||
proj_id = proj["id"]
|
||||
status = proj["status"] or "NEW"
|
||||
print(f"Backfilling project {proj_id} with status '{status}'...")
|
||||
|
||||
# 각 단계별 상태 매핑 결정
|
||||
# 0=FILE_INPUT, 1=SURFACE, 2=ROUTE, 3=PROFILE_CROSS
|
||||
# 4=DESIGN_DETAIL, 5=QUANTITY, 6=ESTIMATION
|
||||
states = ["NOT_STARTED"] * 7
|
||||
|
||||
if status == "NEW":
|
||||
pass
|
||||
elif status in ("FILE_INPUT_PROCESSING", "FILE_INPUT_FAILED"):
|
||||
states[0] = "IN_PROGRESS" if "PROCESSING" in status else "FAILED"
|
||||
elif status == "FILE_UPLOADED":
|
||||
states[0] = "COMPLETE"
|
||||
elif "WF1" in status:
|
||||
states[0] = "COMPLETE"
|
||||
if "ANALYZING" in status:
|
||||
states[1] = "IN_PROGRESS"
|
||||
elif "FAILED" in status:
|
||||
states[1] = "FAILED"
|
||||
else:
|
||||
states[1] = "COMPLETE"
|
||||
elif "WF2" in status:
|
||||
states[0] = "COMPLETE"
|
||||
states[1] = "COMPLETE"
|
||||
if "ANALYZING" in status:
|
||||
states[2] = "IN_PROGRESS"
|
||||
elif "FAILED" in status:
|
||||
states[2] = "FAILED"
|
||||
else:
|
||||
states[2] = "COMPLETE"
|
||||
elif "WF3" in status:
|
||||
states[0] = "COMPLETE"
|
||||
states[1] = "COMPLETE"
|
||||
states[2] = "COMPLETE"
|
||||
if "ANALYZING" in status:
|
||||
states[3] = "IN_PROGRESS"
|
||||
elif "FAILED" in status:
|
||||
states[3] = "FAILED"
|
||||
else:
|
||||
states[3] = "COMPLETE"
|
||||
elif "WF4" in status:
|
||||
states[0] = "COMPLETE"
|
||||
states[1] = "COMPLETE"
|
||||
states[2] = "COMPLETE"
|
||||
states[3] = "COMPLETE"
|
||||
if "ANALYZING" in status:
|
||||
states[4] = "IN_PROGRESS"
|
||||
elif "FAILED" in status:
|
||||
states[4] = "FAILED"
|
||||
else:
|
||||
states[4] = "COMPLETE"
|
||||
elif "WF5" in status:
|
||||
states[0] = "COMPLETE"
|
||||
states[1] = "COMPLETE"
|
||||
states[2] = "COMPLETE"
|
||||
states[3] = "COMPLETE"
|
||||
states[4] = "COMPLETE"
|
||||
if "ANALYZING" in status:
|
||||
states[5] = "IN_PROGRESS"
|
||||
elif "FAILED" in status:
|
||||
states[5] = "FAILED"
|
||||
else:
|
||||
states[5] = "COMPLETE"
|
||||
elif "WF6" in status:
|
||||
states[0] = "COMPLETE"
|
||||
states[1] = "COMPLETE"
|
||||
states[2] = "COMPLETE"
|
||||
states[3] = "COMPLETE"
|
||||
states[4] = "COMPLETE"
|
||||
states[5] = "COMPLETE"
|
||||
if "ANALYZING" in status:
|
||||
states[6] = "IN_PROGRESS"
|
||||
elif "FAILED" in status:
|
||||
states[6] = "FAILED"
|
||||
else:
|
||||
states[6] = "COMPLETE"
|
||||
elif status in ("DONE", "CONFIRMED"):
|
||||
for i in range(7):
|
||||
states[i] = "COMPLETE"
|
||||
|
||||
# DB에 단계별 정보 입력 (ON DUPLICATE KEY UPDATE로 덮어쓰기 안전)
|
||||
for stage_no, stage_key in enumerate(STAGE_KEYS):
|
||||
state = states[stage_no]
|
||||
progress = 100 if state == "COMPLETE" else 0
|
||||
await cursor.execute(
|
||||
"""
|
||||
INSERT INTO project_workflow_stages (
|
||||
project_id, stage_no, stage_key, state, progress_percent
|
||||
)
|
||||
VALUES (%s, %s, %s, %s, %s)
|
||||
ON DUPLICATE KEY UPDATE state = %s, progress_percent = %s
|
||||
""",
|
||||
(proj_id, stage_no, stage_key, state, progress, state, progress),
|
||||
)
|
||||
|
||||
await connection.commit()
|
||||
print("Backfill complete!")
|
||||
return True
|
||||
|
||||
except Exception as e:
|
||||
print(f"Migration / Backfill failed: {e}")
|
||||
await connection.rollback()
|
||||
return False
|
||||
finally:
|
||||
connection.close()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
success = asyncio.run(migrate())
|
||||
sys.exit(0 if success else 1)
|
||||
Reference in New Issue
Block a user