阅读文本 / Reading text
本文使用合成样本演示处理方法。代码已通过隔离环境中的示例检查;这不代表对所有真实文件或产品效果的保证。处理重要文件前,请保留原件,并按文中的边界与验收项复核。
一个扫描 PDF 卡住了,后面的九十九个任务都不动。给请求加超时时间看似解决了问题,实际处理进程却可能仍在后台吃内存。超时至少涉及三个动作:停止等待、停止执行,以及标记产物不可交付。
等待超时不等于工作已终止
subprocess.run(timeout=...)
对直接子进程提供超时处理,但不能泛化为“任意进程树已经被清理”。不同操作系统、启动方式和孙进程行为会影响结果。生产实现需要进程组、容器或作业对象等隔离策略。
先写清楚任务状态契约
下面只模拟状态判定,不启动外部命令、不故意挂起进程。它演示的重点是:达到截止时间后,即使某个工作单元晚到了一份结果,也不能直接把已超时任务改成成功。
from dataclasses import dataclass
@dataclass(frozen=True)
class Decision:
state: str
deliver: bool
terminate_requested: bool
def decide(now, deadline, worker_done, artifact_valid):
if now >= deadline:
return Decision("timed_out", False, not worker_done)
if not worker_done:
return Decision("processing", False, False)
if not artifact_valid:
return Decision("invalid_artifact", False, False)
return Decision("verified", True, False)
assert decide(9, 10, False, False).state == "processing"
assert decide(10, 10, False, False).terminate_requested
assert not decide(11, 10, True, True).deliver
assert decide(9, 10, True, True).deliver
assert decide(9, 10, True, False).state == "invalid_artifact"
这个协议选择在等于截止时间时视为超时。你也可以采用另一种边界,但应写进测试。真实时间比较应使用适合计算间隔的单调时钟,不能让系统时区或墙上时钟调整改变任务预算。
超时后留下哪些证据
需要知道的事
用途
注意
超时阶段
区分下载、解析或翻译
不只记一个 timeout
终止是否确认
防止后台遗留工作
请求终止不等于已退出
临时产物身份
避免误交半成品
不与正式结果共用状态
重试次数
控制总预算
不能每次重新获得无限时间
重试不是自动的下一步
若相同输入每次都在同一步耗尽资源,应隔离样本并排查复杂度问题。只有失败原因可恢复、调用具备适当幂等性时,重试才有意义。用户也应该能区分“服务忙,正在重试”和“输入不支持,需要处理”。
对外翻译任务保留自己的截止策略
接入
OmniDoc(产品入口)
时,客户端等待时间、平台处理状态与文件下载状态应分开表示。页面停止等待,不意味着远端任务不存在;再次点击按钮之前应先查询已知任务,避免重复消耗或产生难以对应的多个结果。
参考:
Python subprocess 的超时行为
。
- 1 -
更新于 2026-10-08