Fix dynamic DB session access

This commit is contained in:
2026-04-16 18:16:20 +08:00
parent fe09153b73
commit f6c8472354
3 changed files with 39 additions and 20 deletions
+11 -7
View File
@@ -8,8 +8,8 @@ from fastapi import APIRouter, Depends, HTTPException
from pydantic import BaseModel, Field from pydantic import BaseModel, Field
from .dependencies import _get_current_user, _require_admin from .dependencies import _get_current_user, _require_admin
from .. import database
from ..config import read_int_env, settings from ..config import read_int_env, settings
from ..database import AsyncSessionLocal
from ..models import AuthUserORM from ..models import AuthUserORM
from ..services.dinsar_production_service import dinsar_production_service from ..services.dinsar_production_service import dinsar_production_service
from ..services.job_queue_service import job_queue_service from ..services.job_queue_service import job_queue_service
@@ -51,6 +51,14 @@ def _get_registry():
return registry return registry
def _new_session():
if database.AsyncSessionLocal is None:
database.init_db()
if database.AsyncSessionLocal is None:
raise RuntimeError("Database session factory is not initialized.")
return database.AsyncSessionLocal()
@router.get("/engines") @router.get("/engines")
async def list_engines(): async def list_engines():
registry = _get_registry() registry = _get_registry()
@@ -184,9 +192,7 @@ async def submit_run(
try: try:
if req.engine_code == "sarscape": if req.engine_code == "sarscape":
if AsyncSessionLocal is None: async with _new_session() as db:
raise RuntimeError("Database session factory is not initialized.")
async with AsyncSessionLocal() as db:
result = await dinsar_production_service.create_run( result = await dinsar_production_service.create_run(
engine_code=req.engine_code, engine_code=req.engine_code,
profile_code=req.profile, profile_code=req.profile,
@@ -239,8 +245,6 @@ async def submit_run(
@router.get("/runs") @router.get("/runs")
async def list_runs(limit: int = 20): async def list_runs(limit: int = 20):
if AsyncSessionLocal is None: async with _new_session() as db:
raise HTTPException(status_code=500, detail="Database session factory is not initialized.")
async with AsyncSessionLocal() as db:
result = await dinsar_production_service.list_runs(db, limit=limit) result = await dinsar_production_service.list_runs(db, limit=limit)
return result return result
+19 -12
View File
@@ -8,6 +8,7 @@ from fastapi import APIRouter, Depends, HTTPException, Request
from fastapi.responses import StreamingResponse from fastapi.responses import StreamingResponse
from pydantic import BaseModel from pydantic import BaseModel
from .. import database
from ..auth_utils import verify_password from ..auth_utils import verify_password
from ..models import AuthUserORM, TaskInfo from ..models import AuthUserORM, TaskInfo
from ..services.dinsar_production_service import dinsar_production_service from ..services.dinsar_production_service import dinsar_production_service
@@ -20,7 +21,6 @@ from ..services.task_service import (
task_service, task_service,
) )
from ..auth_service import SESSION_COOKIE_NAME, get_user_by_session_token from ..auth_service import SESSION_COOKIE_NAME, get_user_by_session_token
from ..database import AsyncSessionLocal
from .dependencies import _require_admin from .dependencies import _require_admin
router = APIRouter() router = APIRouter()
@@ -30,6 +30,14 @@ class ForceCancelRequest(BaseModel):
password: str password: str
def _new_session():
if database.AsyncSessionLocal is None:
database.init_db()
if database.AsyncSessionLocal is None:
raise RuntimeError("Database session factory is not initialized.")
return database.AsyncSessionLocal()
@router.get("/tasks/active", response_model=List[TaskInfo]) @router.get("/tasks/active", response_model=List[TaskInfo])
async def get_active_tasks(limit: int = TASK_ACTIVE_DEFAULT_LIMIT, offset: int = 0): async def get_active_tasks(limit: int = TASK_ACTIVE_DEFAULT_LIMIT, offset: int = 0):
"""获取当前正在运行的所有后台任务""" """获取当前正在运行的所有后台任务"""
@@ -44,12 +52,12 @@ async def stream_active_tasks(request: Request):
"""SSE 端点:每 3s 推送一次活跃任务列表,替代前端轮询。""" """SSE 端点:每 3s 推送一次活跃任务列表,替代前端轮询。"""
# Authenticate via Cookie at connection establishment # Authenticate via Cookie at connection establishment
token = request.cookies.get(SESSION_COOKIE_NAME) token = request.cookies.get(SESSION_COOKIE_NAME)
if token and AsyncSessionLocal: if token:
async with AsyncSessionLocal() as db: async with _new_session() as db:
user = await get_user_by_session_token(db, token) user = await get_user_by_session_token(db, token)
if not user: if not user:
raise HTTPException(status_code=401, detail="Authentication required.") raise HTTPException(status_code=401, detail="Authentication required.")
elif not token: else:
raise HTTPException(status_code=401, detail="Authentication required.") raise HTTPException(status_code=401, detail="Authentication required.")
async def event_generator(): async def event_generator():
@@ -127,14 +135,13 @@ async def force_cancel_task(
if task.status not in ("PENDING", "RUNNING"): if task.status not in ("PENDING", "RUNNING"):
raise HTTPException(status_code=400, detail="任务已结束,无需取消") raise HTTPException(status_code=400, detail="任务已结束,无需取消")
killed_pid = None killed_pid = None
if AsyncSessionLocal is not None: async with _new_session() as db:
async with AsyncSessionLocal() as db: run = await dinsar_production_service.request_cancel(task_id, db=db)
run = await dinsar_production_service.request_cancel(task_id, db=db) if run is not None:
if run is not None: killed_pid = await dinsar_production_service.kill_active_execution_by_task_id(
killed_pid = await dinsar_production_service.kill_active_execution_by_task_id( task_id,
task_id, db=db,
db=db, )
)
await task_service.update_task(task_id, status="CANCELLED", message="管理员强制取消") await task_service.update_task(task_id, status="CANCELLED", message="管理员强制取消")
return { return {
"message": "任务已强制取消", "message": "任务已强制取消",
+9 -1
View File
@@ -17,8 +17,8 @@ logger = logging.getLogger(__name__)
from sqlalchemy import select from sqlalchemy import select
from .. import database
from ..config import settings from ..config import settings
from ..database import AsyncSessionLocal
from ..models import SystemJobORM, DinsarResultORM, HazardPointORM, DinsarTaskItemORM, PsTaskItemORM, SARSceneGeoORM, FloodDetectionORM, WaterDetectionORM, GF3ProcessingORM, AiDiagnosisORM from ..models import SystemJobORM, DinsarResultORM, HazardPointORM, DinsarTaskItemORM, PsTaskItemORM, SARSceneGeoORM, FloodDetectionORM, WaterDetectionORM, GF3ProcessingORM, AiDiagnosisORM
from ..scheduler import scan_data_job from ..scheduler import scan_data_job
from .data_service import data_service from .data_service import data_service
@@ -80,6 +80,14 @@ JOB_TYPE_REBUILD_PSINSAR_CATALOG = "REBUILD_PSINSAR_CATALOG"
COPY_ALLOWED_STATUSES = {"PENDING", "IN_PROGRESS", "COMPLETED", "FAILED"} COPY_ALLOWED_STATUSES = {"PENDING", "IN_PROGRESS", "COMPLETED", "FAILED"}
def AsyncSessionLocal():
if database.AsyncSessionLocal is None:
database.init_db()
if database.AsyncSessionLocal is None:
raise RuntimeError("Database session factory is not initialized.")
return database.AsyncSessionLocal()
def _normalize_copy_statuses(raw_statuses: Any) -> List[str]: def _normalize_copy_statuses(raw_statuses: Any) -> List[str]:
if not raw_statuses: if not raw_statuses:
return ["COMPLETED"] return ["COMPLETED"]