feat: align DInSAR workflow with three-engine task pool

This commit is contained in:
2026-06-15 00:10:00 +08:00
parent b1c59051b9
commit a0388de9d4
15 changed files with 950 additions and 70 deletions
+3 -14
View File
@@ -28,12 +28,6 @@ DINSAR_PRODUCTION_JOB_MAX_ATTEMPTS = read_int_env(
minimum=1,
maximum=20,
)
ISCE2_PRODUCTION_JOB_MAX_ATTEMPTS = read_int_env(
"ISCE2_PRODUCTION_JOB_MAX_ATTEMPTS",
1,
minimum=1,
maximum=10,
)
PYINT_PRODUCTION_JOB_MAX_ATTEMPTS = read_int_env(
"PYINT_PRODUCTION_JOB_MAX_ATTEMPTS",
1,
@@ -49,7 +43,7 @@ LANDSAR_PRODUCTION_JOB_MAX_ATTEMPTS = read_int_env(
class RunJobRequest(BaseModel):
engine_code: str = Field(..., description="Engine code: sarscape / isce2 / pyint / landsar")
engine_code: str = Field(..., description="Engine code: sarscape / pyint / landsar")
profile: str = Field(..., description="Engine profile, for example custom6 / lt1_stripmap / lt1_gamma_dinsar")
root_dir: str = Field(..., description="Windows root directory")
num_to_process: int = Field(default=0, ge=0, description="How many tasks to process; 0 means all")
@@ -251,7 +245,6 @@ async def submit_run(
from ..services.job_handlers import (
JOB_TYPE_IDL_RUN_DINSAR,
JOB_TYPE_ISCE2_RUN,
JOB_TYPE_LANDSAR_RUN,
JOB_TYPE_PYINT_RUN,
)
@@ -263,18 +256,14 @@ async def submit_run(
job_type = JOB_TYPE_IDL_RUN_DINSAR
max_attempts = DINSAR_PRODUCTION_JOB_MAX_ATTEMPTS
create_managed_run = True
elif req.engine_code in {"isce2", "pyint", "landsar"}:
elif req.engine_code in {"pyint", "landsar"}:
if hasattr(engine, "normalize_extra"):
try:
payload["extra"] = engine.normalize_extra(payload["extra"])
except ValueError as exc:
raise HTTPException(status_code=400, detail=str(exc)) from exc
normalized_extra = dict(payload["extra"])
if req.engine_code == "isce2":
job_type = JOB_TYPE_ISCE2_RUN
max_attempts = ISCE2_PRODUCTION_JOB_MAX_ATTEMPTS
create_managed_run = True
elif req.engine_code == "pyint":
if req.engine_code == "pyint":
job_type = JOB_TYPE_PYINT_RUN
max_attempts = PYINT_PRODUCTION_JOB_MAX_ATTEMPTS
create_managed_run = True
+50
View File
@@ -20,6 +20,7 @@ from ..services.result_catalog_service import (
TASK_TYPE_REBUILD_DINSAR_CATALOG,
result_catalog_service,
)
from ..services.dinsar_intermediate_cleanup_service import dinsar_intermediate_cleanup_service
from ..services.task_service import task_service
from .dependencies import (
_add_operation_audit_log,
@@ -233,6 +234,42 @@ async def list_dinsar_products(
)
@router.get("/dinsar-products/pairs")
async def list_dinsar_product_pairs(
limit: int = 100,
offset: int = 0,
engine_code: Optional[str] = None,
status: Optional[str] = None,
query: Optional[str] = None,
include_legacy: bool = False,
current_user: AuthUserORM = Depends(_get_current_user),
db: AsyncSession = Depends(get_db),
):
_ = current_user
return await result_catalog_service.list_product_pairs(
db,
limit=limit,
offset=offset,
engine_code=engine_code,
status=status,
query=query,
include_legacy=include_legacy,
)
@router.get("/dinsar-products/pairs/{pair_key}/cleanup-intermediates/plan")
async def get_dinsar_pair_intermediate_cleanup_plan(
pair_key: str,
current_user: AuthUserORM = Depends(_get_current_user),
db: AsyncSession = Depends(get_db),
):
_ = current_user
plan = await dinsar_intermediate_cleanup_service.build_pair_plan(db, pair_key=pair_key)
if int(plan.get("product_count") or 0) == 0:
raise HTTPException(status_code=404, detail="No D-InSAR products found for pair_key")
return plan
@router.get("/dinsar-products/{product_db_id}")
async def get_dinsar_product_detail(
product_db_id: int,
@@ -246,6 +283,19 @@ async def get_dinsar_product_detail(
return detail
@router.get("/dinsar-products/{product_db_id}/cleanup-intermediates/plan")
async def get_dinsar_product_intermediate_cleanup_plan(
product_db_id: int,
current_user: AuthUserORM = Depends(_get_current_user),
db: AsyncSession = Depends(get_db),
):
_ = current_user
plan = await dinsar_intermediate_cleanup_service.build_product_plan(db, product_db_id=product_db_id)
if plan is None:
raise HTTPException(status_code=404, detail="Result product not found")
return plan
@router.get("/dinsar-products/{product_db_id}/preview")
async def get_dinsar_product_preview(
product_db_id: int,
+9 -1
View File
@@ -28,6 +28,7 @@ from ..models import (
TimeseriesStackPlanItemORM,
TimeseriesStackPlanORM,
)
from ..services.dinsar_engine_matrix import build_engine_results_for_task_items
from .dependencies import (
_add_operation_audit_log,
_refresh_dinsar_batch_summary,
@@ -361,7 +362,14 @@ async def list_dinsar_batch_items_endpoint(
.offset(safe_offset)
.limit(safe_limit)
)
return [DinsarTaskItem.model_validate(i) for i in result.scalars().all()]
items = result.scalars().all()
engine_results_by_item_id = await build_engine_results_for_task_items(db, items)
payload: List[DinsarTaskItem] = []
for item in items:
row = DinsarTaskItem.model_validate(item)
row.engine_results = engine_results_by_item_id.get(int(item.id or 0), {})
payload.append(row)
return payload
@router.patch("/task-batches/dinsar/{batch_id}/complete-all", response_model=DinsarTaskBatch)