1
This commit is contained in:
@@ -314,22 +314,55 @@ class TaskExecutor:
|
||||
async def cancel(self, execution_id: str) -> bool:
|
||||
"""向子进程发送终止信号。
|
||||
|
||||
如果进程仍在内存中,发送 terminate 信号;
|
||||
如果进程已不在内存中(如后端重启后),但数据库中仍为 running,
|
||||
则直接将数据库状态标记为 cancelled(幽灵记录兜底)。
|
||||
|
||||
Returns:
|
||||
True 表示成功发送终止信号,False 表示进程不存在或已退出。
|
||||
True 表示成功取消,False 表示任务不存在或已完成。
|
||||
"""
|
||||
proc = self._processes.get(execution_id)
|
||||
if proc is None:
|
||||
return False
|
||||
# subprocess.Popen: poll() 返回 None 表示仍在运行
|
||||
if proc.poll() is not None:
|
||||
return False
|
||||
if proc is not None:
|
||||
# 进程仍在内存中
|
||||
if proc.poll() is not None:
|
||||
return False
|
||||
logger.info("取消 ETL 子进程 [%s], pid=%s", execution_id, proc.pid)
|
||||
try:
|
||||
proc.terminate()
|
||||
except ProcessLookupError:
|
||||
return False
|
||||
return True
|
||||
|
||||
logger.info("取消 ETL 子进程 [%s], pid=%s", execution_id, proc.pid)
|
||||
# 进程不在内存中(后端重启等场景),尝试兜底修正数据库幽灵记录
|
||||
try:
|
||||
proc.terminate()
|
||||
except ProcessLookupError:
|
||||
return False
|
||||
return True
|
||||
conn = get_connection()
|
||||
try:
|
||||
with conn.cursor() as cur:
|
||||
cur.execute(
|
||||
"""
|
||||
UPDATE task_execution_log
|
||||
SET status = 'cancelled',
|
||||
finished_at = NOW(),
|
||||
error_log = COALESCE(error_log, '')
|
||||
|| E'\n[cancel 兜底] 进程已不在内存中,标记为 cancelled'
|
||||
WHERE id = %s AND status = 'running'
|
||||
""",
|
||||
(execution_id,),
|
||||
)
|
||||
updated = cur.rowcount
|
||||
conn.commit()
|
||||
finally:
|
||||
conn.close()
|
||||
if updated:
|
||||
logger.info(
|
||||
"兜底取消 execution_log [%s]:数据库状态从 running → cancelled",
|
||||
execution_id,
|
||||
)
|
||||
return True
|
||||
except Exception:
|
||||
logger.exception("兜底取消 execution_log [%s] 失败", execution_id)
|
||||
return False
|
||||
|
||||
|
||||
# ------------------------------------------------------------------
|
||||
# 数据库操作(同步,在线程池中执行也可,此处简单直连)
|
||||
|
||||
Reference in New Issue
Block a user