Sunday 的面试指南

用户上传文件后,解析和建索引要几分钟,异步任务该怎么设计?

🧑‍💻 面试官:做一个知识库,用户上传一份扫描 PDF。OCR、切片和建索引要三分钟。前端的上传请求一直等到全部处理完吗?

🙋‍♂️ 我:不会。上传请求先确认文件保存成功,创建一条处理任务并返回任务 ID。解析和建索引在后台跑,页面根据任务状态展示“处理中”“可使用”或“失败”。

🧑‍💻 面试官:用户等得着急,又上传了一遍;消息队列还把同一条消息投递了两次。会不会建出两份索引?

🙋‍♂️ 我:如果只靠“队列只投一次”就会出问题。需要给文件版本和任务建立幂等标识,让重复上传或重复消费能找到同一份处理结果,至少不能把同一个版本重复发布成多份可检索文档。

🧑‍💻 面试官:Worker 在写了一半索引后崩了,任务页面显示什么?

🙋‍♂️ 我:不能只看队列消费成功没有。要有可查询的任务记录和阶段状态;重试时能识别已完成的步骤。新索引没完整构建和校验前,不把半成品标成“可使用”。

这题考的不是“会不会用队列”,而是一个长任务从接收、重试到最终可用,系统如何始终说得清它的状态。

面试速答(60 秒版)

文件上传和解析建索引要分开。上传接口把文件可靠保存下来,再创建一条任务,返回文件 ID、任务 ID 和当前状态;OCR、切片、Embedding、写索引由后台 Worker 执行。页面通过查询状态或订阅事件展示进度,但“上传成功”不能写成“知识库已经可以问答”。

异步链路要重点处理重复和失败。队列消息可能重复投递,Worker 也可能跑一半崩掉,所以每次处理都要绑定文件版本和幂等键。步骤完成后记录检查点;重试时跳过已确认完成的部分,或者先清理该版本的临时产物再重建。索引完整且通过验证以后,才把这个版本切换成可检索。

最后看能否回答三个问题:这个文件现在处理到哪一步?失败后是否可以安全重试?同一文件版本被提交两次会不会出现重复或半成品?这些比“用了什么消息队列”更能说明设计是否可靠。

知识点详解:把“上传成功”和“可以检索”分成两件事

为什么不能让请求一直等

假设用户上传一份 300 页的扫描 PDF,OCR 需要一分钟,切片和向量化又要两分钟。如果 HTTP 请求一直等,用户关掉页面、网关超时或者手机网络断了,都会让他以为上传失败。更麻烦的是,后台可能还在跑,用户再次点击上传后又启动第二次处理。

一个更清楚的边界是:上传接口只承诺文件已保存、任务已登记。返回 file_id 和 job_id 以后,后续处理进入异步任务。前端可以查询任务状态,也可以订阅状态变化;但这些只是展示方式,真正的状态要以服务端持久化记录为准。

任务记录需要讲清楚“处理到哪儿了”

最小的状态不必设计得特别花。可以是“等待处理 → 解析中 → 建索引中 → 可使用”,出错进入“失败”;另存具体阶段、错误原因、尝试次数、文件版本和更新时间。状态的含义要面向用户,而不只是面向 Worker。

例如“索引写入完成”未必等于“可使用”。还要确认这次文件的分段数量、索引写入结果、文档版本是否一致,以及检索服务能否读到这个版本。只有通过这些检查,才把版本发布给问答侧。旧版本如果正在服务,可以继续保留,等新版准备好再切换;不要在构建新版时让半成品进入检索。

文件上传后经过 OCR、切片、建索引和完整性校验才会进入问答检索,崩溃的半成品被拦截

队列会帮你解耦,不会替你保证只执行一次

常见队列采用至少一次投递语义:同一条任务可能被 Worker 收到不止一次。对象存储事件也可能重复或乱序。即使选用的组件有去重能力,应用仍应考虑崩溃发生在“索引写入成功、任务状态没来得及更新”这个空档。

做法是让每次处理都能回答“我在处理哪个文件的哪个版本”。同一个 file_id + version 的任务只能有一个有效发布结果;重复消息先查状态和已有产物。写索引时使用稳定的文档/片段标识,避免重试追加另一份相同片段。中间产物与最终发布版本分开,必要时重建或清理未发布版本。

这里的“幂等”不是宣称 Worker 一定只跑一次,而是说重复跑以后,对用户可见的最终结果仍然只有一份正确版本。

失败之后,用户和运维都要知道怎么办

OCR 服务短暂故障可以有限次数重试;文件损坏、格式不支持,重试十次也不会好。任务记录要保留阶段和可读错误,同时区分可重试与不可重试。重试次数、退避和超时达到上限后进入失败状态,避免任务永远显示“处理中”。

验证时可以故意在每个阶段杀掉 Worker,或者重复投递同一条消息。检查任务能否最终进入“可使用/失败”,索引里是否有重复片段,失败版本是否被误发布。页面刷新后还能查询到同一个任务状态,才算这一条链路真正闭合。

面试官继续追问

上传接口返回 200,就能提示“知识库已更新”吗?

不能。它最多说明文件保存和任务创建成功。应分别展示“上传成功,正在处理”和“已完成,可以检索”。否则用户立刻提问,检索不到新文件,会认为系统丢了资料。

队列消息重复,简单地在 Worker 开始时查一次任务状态够吗?

不够。两个 Worker 可能同时查到“等待处理”。还需要原子抢占/租约、稳定的版本标识和幂等写入;即使并发执行,最终也不能让两份结果同时发布。具体锁与事务实现取决于存储系统。

同一份文件重新上传了新版,旧版马上删吗?

通常先别删。新版处理失败时,旧版还可能是唯一可用的资料。可以把“正在构建的版本”和“当前对外服务的版本”分开,待新版本验证通过后切换,再按保留策略清理旧版本。

面试速记卡

  • 上传成功:文件已保存、任务已创建,不代表已经可以检索。
  • 异步链路:后台做 OCR、切片、Embedding 和建索引,前端查询持久化状态。
  • 重复处理:按文件版本做幂等,接受消息可能重复投递。
  • 发布门槛:完整构建和校验后再切换可检索版本,不暴露半成品。
  • 故障验证:重复投递、Worker 中途崩溃、页面刷新与新版处理失败都要测试。
简历汪永久免费在线制作简历,模板直接套用、导出无水印,永久免费、下载免费,不需要付费解锁任何功能。去写简历