经营导出、库存龄期、应收账龄一类大报表,如果堵在 HTTP 请求里,浏览器只会等到 504。Odoo 19 的正确体验是:用户点一次「导出/计算」→ 立刻拿到「已加入队列」反馈 → 后台 worker 写出 ir.attachment → 用活动或邮件通知下载。本文按可落地顺序写清:任务模型怎么设计、参数如何序列化、权限如何按发起人隔离、限流与失败重试怎么配,以及验收时要看哪些指标。
为什么必须异步,而不是把超时调大
反向代理 proxy_read_timeout、Odoo limit_time_cpu / limit_time_real 可以「撑」住一次长请求,但撑不住并发:午后十个人同时导出,Web worker 被占满,登录和开单也会变慢。异步把「计算」从请求线程挪到队列消费者,网关只等待入队成功(通常 < 1 秒)。若环境安装了企业队列作业,用 job 通道;否则可用专用 ir.cron + 任务表轮询,但务必给任务写状态机,禁止无状态死循环扫全库。
- 交互请求:短超时,失败要可读。
- 已知长任务:只同步做参数校验与入队。
- 结果下载:走附件或签名 URL,不走内存流经 worker。
任务记录与可序列化参数
建议自建轻量模型(或复用现有 job 表)至少包含:name、state(draft/queued/running/done/failed)、user_id、company_id、筛选条件 JSON、attachment_id、error_message、queued_at / done_at。筛选条件只存原始 domain / 日期区间 / 报表类型,不要存不可 pickle 的 recordset。消费者里用 env['sale.order'].with_company(...).search(domain) 重建查询。同一业务键(用户+报表类型+参数哈希)若已有 queued/running,应拒绝二次入队或返回原任务,避免重复点击造出十份相同 Excel。
完成通知与附件权限
完成后创建 ir.attachment,res_model/res_id 挂在任务记录上,public=False。用 mail.activity 或 mail.mail 通知发起人,链接指向任务表单或受控下载路由。权限规则:只有发起人、同公司管理员或明确安全组可读附件;禁止把结果挂到「全公司可读」的公告上。敏感财务导出建议设过期策略:例如 7 天后由清理 cron 把附件 datas 清空并写审计备注。
限流、失败与毒丸任务
同一 user_id 并发任务数设上限(例如 2);超大时间范围在入队前拦截并提示缩小筛选。失败要写可读 error_message(截断 traceback 前 2KB),状态置 failed,并给发起人活动。自动重试用指数退避,且同一任务最多 N 次;连续失败标「毒丸」,需人工点「重试」才再入队。运维侧监控:队列深度、平均耗时、失败率、单用户占用槽位数。
落地步骤(可照做)
- 选定一条最痛的报表(如库存估值导出)做试点,先不铺全站。
- 加「导出」按钮:校验参数 → 建任务 → 入队 → 通知「可在我的导出任务查看」。
- 消费者写 Excel/CSV 到附件;完成后活动提醒。
- 压测:同时 10 用户提交,确认 Web 仍可登录开单。
- 写 SOP:失败如何看错误、如何重试、谁有权下载别人的导出。
验收标准
- 30 万行量级导出不拖垮 Web worker;页面在 2 秒内返回入队成功。
- 完成后仅发起人(及授权角色)能打开
ir.attachment。 - 重复点击同一参数组合不会产生多份并行任务(或明确合并)。
- 人为抛错后状态=failed,发起人收到活动,且可一键重试。
用户可见的状态机文案
任务列表显示:排队中 / 计算中 / 已完成可下载 / 失败可重试。失败文案避免堆栈原文,
给「可能原因 + 建议缩小筛选 + 联系人」。下载审计:谁在何时下载了哪份 ir.attachment。
对财务类导出启用二次确认或二次认证。定期清理过期附件并保留审计行。
若队列中间件升级,先在预生产跑「十万行导出」回归,再改生产消费者并发数。
中国Odoo网|对照 Odoo 19 企业版队列/异步报表实践整理:先入队再计算,附件按人授权,限流与失败可观测。