feat: 文件夹批量处理引擎(后端)
- BatchWorker 单线程轮询 batch_jobs 表,处理 source=batch 的运行, 与主调度器互不抢占(next_queued_run 排除 batch 来源) - 直接读取用户所选文件夹下的视频逐个执行流水线,不上传到工作目录; 中间态与产物落在视频旁同名文件夹,batch.done.json 完成标记去重 - 支持暂停/继续、失败容错(单视频失败不阻塞后续)、删除任务只清库 - 孤儿清理跳过 source=batch 运行,防止误删用户视频文件夹 - workflow_runs 新增 source 列(upload/batch),旧库自动迁移
This commit is contained in:
+12
-3
@@ -21,10 +21,11 @@ from fastapi.middleware.cors import CORSMiddleware # noqa: E402
|
||||
from fastapi.staticfiles import StaticFiles # noqa: E402
|
||||
|
||||
from wov_app import registry
|
||||
from wov_app.config import DB_PATH, STORAGE_DIR, WORKSPACE_ROOT
|
||||
from wov_app.batch import BatchWorker
|
||||
from wov_app.config import BATCH_ENABLED, DB_PATH, STORAGE_DIR, WORKSPACE_ROOT
|
||||
from wov_app.db import Database
|
||||
from wov_app.maintenance import OrphanCleaner
|
||||
from wov_app.routers import apps, workflows
|
||||
from wov_app.routers import apps, batch, workflows
|
||||
from wov_app.scheduler import WorkflowScheduler
|
||||
from wov_app.seed import seed_default_workflows
|
||||
|
||||
@@ -50,12 +51,19 @@ async def lifespan(app: FastAPI):
|
||||
# 孤儿数据清理默认开启,定时清除死数据;测试可关闭。
|
||||
if os.getenv("WOV_CLEANUP_ENABLED", "1") == "1":
|
||||
cleaner.start()
|
||||
# 批量处理引擎:处理用户所选文件夹的批量任务(source=batch 的运行),
|
||||
# 与主调度器互不抢占;默认开启,测试可关闭。
|
||||
batch_worker = BatchWorker(db)
|
||||
if os.getenv("WOV_BATCH_ENABLED", "1") == "1":
|
||||
batch_worker.start()
|
||||
# 共享对象挂到 app.state,路由通过 Depends 延迟获取。
|
||||
app.state.db = db
|
||||
app.state.scheduler = scheduler
|
||||
app.state.cleaner = cleaner
|
||||
app.state.batch = batch_worker
|
||||
yield
|
||||
# 退出时先停调度器与清理器,避免残留后台线程。
|
||||
# 退出时先停批量引擎、调度器与清理器,避免残留后台线程。
|
||||
batch_worker.stop()
|
||||
cleaner.stop()
|
||||
scheduler.stop()
|
||||
|
||||
@@ -72,6 +80,7 @@ app.add_middleware(
|
||||
|
||||
app.include_router(workflows.router)
|
||||
app.include_router(apps.router)
|
||||
app.include_router(batch.router)
|
||||
|
||||
|
||||
@app.get("/health")
|
||||
|
||||
Reference in New Issue
Block a user