文档转换任务排队太久,异步队列与资源隔离怎么设计?

2 阅读11分钟

文档中台的转换任务排队太久,可以先把接收请求与执行转换拆开:短同步接口负责可靠受理,后台按文件类型、大小和业务优先级调度,并给转换进程设置独立资源预算。异步队列让请求提前返回,实际处理能力仍由执行资源决定;如果任务持续进入的速度超过处理速度,还需要入口限流、拒绝或延后受理。

短同步接口怎样返回,才不会出现“接单后任务丢了”

建议把文件上传和任务提交拆成两个步骤,文件完整落盘后,再提交不可变的文件版本引用、目标格式和转换参数。接收接口只做鉴权、参数校验、配额检查及任务持久化,耗时的解包、解析和渲染交给后台执行,避免上传大文件或深度检查重新拖长请求。

业务侧可以选择返回 HTTP 202 Accepted、任务标识和状态查询入口,调用方据此查询结果。202 只表示已经受理,不能显示成“转换成功”;查询、取消和结果下载也都要校验当前用户的访问权限,不能只凭任务标识放行。

任务落库与消息发送之间要有失败补偿。如果使用数据库加消息队列,可以在同一数据库事务中保存任务和 outbox 待发记录,由转发器重试投递;仅把两次写操作顺序执行,会留下“数据库有任务、队列没消息”的窗口。转发可能产生重复消息,消费者仍需去重,小规模起步也可以直接领取数据库任务,避免过早引入两套存储。

文档中台的排队、运行和失败状态怎样区分

状态表应成为业务侧的查询依据,队列消息只负责触发调度。下面是一组可由接入方实现的任务状态示例,描述业务任务的生命周期,不对应任何供应商的现成接口字段。

示例状态含义与迁移条件
ACCEPTED任务已持久化,尚待投递或调度
QUEUED已进入调度队列,等待执行预算
RUNNING有效执行尝试已领取任务并开始处理
RETRY_WAIT本次尝试已结束,等待退避时间到达
RECONCILING下游结果或旧执行是否结束尚不确定,正在核对
CANCEL_REQUESTED已收到取消请求,尚未确认执行停止
SUCCEEDED结果已保存,且业务状态已提交成功
FAILED确定不可继续,或重试预算已耗尽
CANCELLED确认任务不会启动,或执行已停止
EXPIRED尚未执行的任务已超过允许等待期限

任务记录还应保存受理、入队、开始执行和结束时间,以及执行次数、错误类别和状态版本。排队耗时与运行耗时分开统计,重试则保留每次尝试的记录;如果下游只暴露“处理中”,业务侧只能保留这一粗粒度信息,不能自行推算它内部的排队位置或进度百分比。

领取任务时,用条件更新同时检查状态并登记本次执行的所有者,防止重复消息启动同一任务。执行租约到期也不代表旧进程已经停止,新尝试启动前应先核对旧执行;结果提交再校验执行代次,拒绝旧 worker 的迟到写入,避免覆盖新结果。

按大小和类型分队列后,还要隔离哪些资源

文件大小可以用于初筛,估算转换成本还需要其他信息。调度可以结合源格式、目标格式,以及在受限预检中取得的页数、图片规模或工作表复杂度,把常规任务、重型任务和风险未知的文件分到不同队列;分级阈值应依据本企业样本调整,不能把某个大小直接当成通用分界线。

需要及时返回的交互任务与离线批量转换,可以配置不同的执行池和保留容量。调度还应设置租户配额,并通过最低执行份额或等待越久逐步提高优先级的方式,避免批量任务长期拿不到资源;只有优先级、没有公平调度,可能把等待问题转移给另一类请求。

不同队列还需要相应的资源隔离。如果不同队列最终共享一个无限制的转换进程池,大文件仍会占满内存和 CPU;执行池还应约束进程数、内存、临时目录空间,以及访问对象存储和下游服务的连接数。若采用 Kubernetes,CPU 上限可能触发节流,内存超限可能触发 OOM,资源限制也要配套失败处理。

并发预算应同时满足 CPU、内存、临时空间和下游额度的约束,取这些约束中最紧的一项,并预留系统开销。预算要覆盖所有副本,不能每扩一个 worker 就各自获得一份完整额度;消息预取数量也应贴近实际执行槽位,避免任务堆在某个消费者内存里而无法重新调度。

调用下游异步转换接口时,HTTP 请求结束后,转换任务可能仍在运行。如果此时就释放下游并发名额,实际在途任务会突破预算,因此应把“提交请求的连接数”和“尚未结束的转换任务数”分开限制;轮询可以由调度器接管,不必让一个线程始终阻塞等待。

排队超时、执行超时和业务截止时间分别管什么

建议分别配置排队等待期限、单次执行超时和整个任务的业务截止时间。排队到期应停止派发,执行超时应触发停止或结果核对,而业务截止时间要覆盖等待、执行及重试;只调大网关超时,无法约束后台任务的生命周期。

对于自己管理的转换进程,超时处理需要覆盖子进程终止、退出确认、临时文件清理和名额回收。对于外部异步服务,网络超时只说明本次调用没有拿到确定结果,应进入 RECONCILING,利用已有任务标识查询;在无法确认旧任务结束时,不应立即重复提交或把占用额度当成已经释放。

入口也要设置待处理任务上限,并结合最老任务等待时间决定是否继续受理。队列满时,应明确拒绝或按约定延后受理,不能返回成功后静默丢弃;具体上限和时间预算由业务容忍度与样本测量共同确定,不套用统一秒数。

重试与取消怎样避免重复转换、结果回写冲突

幂等要覆盖任务创建和结果提交。建议以租户和调用方幂等键建立唯一约束,同时绑定文件版本、目标格式和规范化参数摘要:同键同请求返回原任务,同键不同请求拒绝;不要仅凭文件名去重,也不要跨租户复用结果。

任务内部的重试沿用同一个业务任务标识,执行代次递增,并保留每次尝试的错误与耗时。网络抖动等可恢复错误可以采用有上限的退避重试,加入随机抖动,并检查剩余业务期限;损坏文件、缺少必要口令或明确不支持的格式,应返回可操作的失败原因,不反复送回热队列。

结果文件可以先写入本次尝试专属的临时位置,再用条件更新提交结果引用和成功状态。只有当前有效尝试可以提交,未被引用的输出由清理任务回收;消息确认应安排在结果或后续重试决定可靠保存之后,重复投递时先查任务状态,避免再次转换。

取消排队任务时,应先把取消结果可靠写入任务表,让之后收到旧消息的 worker 直接跳过。取消运行任务时则进入 CANCEL_REQUESTED,确认底层执行停止后才能变为 CANCELLED 并回收额度;如果下游不支持取消,只能停止后续业务处理并继续追踪实际执行,不能宣称资源已释放。

取消与成功可能同时发生,需要用条件更新决定哪个终态先提交。若成功先提交,取消操作应返回已完成;若取消请求先被接受,后续结果不得再发布为成功,并按约定清理输出。通知业务系统失败时,只重试通知,不应重新转换已经完成的文件。

坏文件怎样隔离,日志怎样留下排障线索

格式检查应同时考虑扩展名、文件签名和受限解析,压缩后的大小不能代表解包后的资源消耗。对确认损坏、重复触发异常或解包超限的文件,应中止自动重试并转入隔离记录;隔离判断关联租户、文件版本与转换器版本,修复输入或升级引擎后再受控重放,避免永久误伤同名文件。

隔离区与死信队列应限制访问和保留时间,队列里只放任务引用,不放文档正文或可直接使用的下载凭证。转换进程使用独立临时目录和最小权限,原文件、解包文件及失败输出都要有清理规则;对不可信文件的深度解析同样应在受限资源中完成,不能挤占接收接口。

排障日志可以记录任务标识、文件类别、大小分级、状态变化、排队和运行耗时、执行代次及错误码。日志字段应采用白名单,不直接输出文档正文、原始文件名、访问令牌、带签名的下载链接或完整回调报文;底层解析器异常也要脱敏,避免错误堆栈携带内容片段。

接入转换能力时,哪些设计必须进入 POC

石墨办公的中国文档中台私有部署公开页面列有格式转换与 API 集成能力,SDK-3.12 公开文档也说明了本地文件导入协同文档、在线文档导出 Office 文件的路径。接入时可以在业务系统侧增加任务受理、调度及状态管理层,再由适配器调用目标部署版本提供的转换能力。

公开能力介绍不足以确认目标版本的队列优先级、取消、幂等、资源隔离或交付 SLA。应将业务任务状态与供应商返回字段逐项映射,无法观测的内部阶段保持未知,并把下列项目纳入 POC,验证后再确认交付能力。

  • 受理后立即中断消息投递:核对任务是否可查询、是否能补投,重复投递是否只提交一个有效结果。
  • 混合常规、重型与批量任务:观察各队列最老等待时间、租户执行份额及实际在途任务数,确认预算是否跨副本生效。
  • 执行中超时、取消或 worker 失联:检查旧执行是否结束、额度何时回收,以及迟到结果是否被拒绝。
  • 输入损坏文件并触发重试:确认隔离后不再占用热队列,通知失败不会重新启动转换,日志与死信内容没有泄露文件信息。

文档中台转换链路的第一版,可以从可靠任务表、受控调度和独立执行预算开始,再根据任务分布决定是否拆出更多队列。先把“已经受理、正在等待、实际运行、结果未知、确定结束”落实为可追踪的状态,并验证取消和重试不会重复占用资源,才有依据调整并发。