☰
在 Elixir 中为 Xberg 文档抽取配置超时:extraction_timeout_secs 实战与原理
2026/9/28 2:29:00 网站建设 项目流程
  • 后端
  • AI 应用
  • NLP

【免费下载链接】xberg

Polyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with CLI, REST API, and MCP server.

项目地址:https://gitcode.com/gh_mirrors/kr/xberg
点击查看免费下载

本文以 Xberg 仓库中 Elixir 契约测试片段(config_extraction_timeout.md)为主线,讲解如何在 Elixir 调用中为单个文档的抽取过程设置超时上限(extraction_timeout_secs),说明该配置的默认值、生效范围与超时后的行为,并结合 Rust 核心源码验证其底层实现。读完本文,你将能在自己的 Elixir / 混合技术栈管道中正确配置超时、读懂超时错误,并知道何时需要把它设为null或调大。

超时配置是文档抽取的资源安全阀

Xberg 用 Rust 实现文档抽取核心,可以从 URI、本地文件或内存字节中抽取文本、元数据、表格与结构化数据。一次抽取可能非常耗时:例如大型扫描件要做逐页 OCR、深嵌套压缩包要递归展开、超大表格要解析数百万单元格。如果没有兜底机制,一个极端输入可能长时间占用线程与内存。extraction_timeout_secs正是 Xberg 提供的单文档超时配置:达到时限后该输入会被取消并返回超时错误,避免"病态文件"无限期耗尽调用方资源。

在 Elixir 绑定中,该字段通过 JSON 配置字符串传入Xberg.extract/2(其底层调用 Xberg.Native.extract_async/2),既可以用于单文档抽取,也可以作为批处理的公共配置。

关联文档与测试契约

本篇文章对应的原始素材是 Elixir 契约测试片段,其契约描述为:

Tests that extraction_timeout_secs config field is accepted and does not affect fast extractions

即验证两点:

  1. extraction_timeout_secs配置字段能被正确接受并解析;
  2. 该超时不会影响快速完成的抽取——正常文档仍然完整返回内容。

仓库中对应的 JSON 契约 config_extraction_timeout.json 给出了完整定义:它通过 mock 服务器返回test_documents/pdf/fake_memo.pdf,以 URI 方式提交抽取,并断言results[0].mime_type等于application/pdf、results[0].content长度不小于 10。同一个契约在所有受支持语言绑定(C、C#、Dart、Go、Java、Python、Ruby、Rust、Swift、TypeScript、Wasm、Zig 等)中均有对应的 snippets-generated 片段,Elixir 是其中之一。

Elixir 中的最小可用示例

契约片段展示了最简洁的调用方式——把 JSON 配置字符串直接作为第二个参数传给Xberg.extract/2:

input_value = %Xberg.ExtractInput{kind: "uri", uri: "https://example.com/pdf/fake_memo.pdf"} result = Xberg.extract_async(input_value, "{\"extraction_timeout_secs\":300}") IO.inspect(Enum.at(result.results, 0).mime_type) IO.inspect(Enum.at(result.results, 0).content)

在实际项目中,更常用的是 Elixir 绑定的高阶封装 Xberg.extract/2,它接受 keyword 列表:

input = %{ kind: "uri", uri: "https://example.com/pdf/fake_memo.pdf" } config = %{ extraction_timeout_secs: 300 } # input / config 为 map 或二进制 JSON 字符串均可,绑定内部会用 Jason 编码 {:ok, result} = Xberg.extract(input: input, config: config) IO.inspect(Enum.at(result["results"], 0)["mime_type"]) IO.inspect(Enum.at(result["results"], 0)["content"])

两种写法的关键点相同:

  • 输入结构:kind: "uri"表示按 URI 抽取(本地路径、file://或 HTTP(S) 地址均可);kind: "bytes"表示内存字节(配合mime_type与可选filename)。
  • 配置传递:配置以 JSON 字符串(契约写法)或可编码为 JSON 的数据结构(封装写法)传入,extraction_timeout_secs是该 JSON 中一个顶层数字字段。
  • 结果读取:返回的ExtractionResult信封包含results、errors、summary等字段;单文档场景读取Enum.at(results, 0).mime_type与.content即可。

默认值:600 秒而非无限制

在 Rust 核心中,该字段定义于 ExtractionConfig,注释明确说明它是"批处理时每个文件的默认超时(秒)",并通过#[serde(default = "ExtractionConfig::default_extraction_timeout")]指定默认值。对应的默认函数 default_extraction_timeout 返回Some(600),即10 分钟:

pub fn default_extraction_timeout() -> Option<u64> { Some(600) }

默认值是Some(600)而非None,意味着不显式配置时超时依然生效——这是刻意设计:600 秒能在"防止病态文件无限运行"(如深嵌套压缩包、百万级单元格表格、对抗性 PDF)与"给慢速路径留足余量"(如基于 VLM 的 OCR、大型扫描文档)之间取得平衡。注释还提到,此前默认曾是 60 秒,后来提升到 600 秒以容纳这些慢速路径。

字段类型为Option<u64>,因此:

  • "extraction_timeout_secs": 300—— 显式设 300 秒;
  • 缺省 —— 继承默认 600 秒;
  • "extraction_timeout_secs": null——显式禁用单文档超时,仅推荐用于完全可信的输入或长时间运行的工作负载。

超时在核心中的实现机制

extraction_timeout_secs不只是一个"建议值",它在 Rust 核心的多个调用点被真实执行。以内存字节抽取路径 core/extractor/bytes.rs 为例:

  1. 若配置了超时且没有调用方提供的取消令牌,先通过ensure_cancel_token()安装内部CancellationToken;
  2. 用tokio::time::timeout(Duration::from_secs(secs), extraction_future)包裹抽取 Future;
  3. 超时触发时调用token.cancel(),并返回XbergError::Timeout { elapsed_ms, limit_ms },其中elapsed_ms为实际耗时,limit_ms为配置的毫秒上限。

批处理路径在 engine/extract_impl.rs 的run_batch_item与finalize_shared_item中采用同样的模式:外层 timeout 包裹 +cancel_token协同取消,并在成功时把耗时写入metadata.extraction_duration_ms。由此可以确认超时的两个实现事实:

  • 超时是协同取消(cooperative cancellation):token.cancel()只是请求在下一个取消检查点停止,具体停止延迟取决于正在运行的抽取器与操作,并非毫秒级强制中断;
  • 超时错误与其他错误隔离:达到时限返回的是类型化的XbergError::Timeout,与该输入本身解析失败的错误分开,便于调用方区分"太慢被掐断"与"文档本身有问题"。

从代码结构看,extraction_timeout_secs还参与 REST 异步作业:服务端配置 ServerConfig 中有job_timeout_secs(默认同样 600 秒),作为POST /extract-async作业的兜底超时——当请求配置没有钉死extraction_timeout_secs时使用;且显式的null并不会变成"无限制",仍会回落到服务端上限,因为无界作业对共享服务是 DoS 风险(见 api/types.rs)。

超时不会干扰快速抽取

回到契约测试的核心断言——"does not affect fast extractions":对一个毫秒级完成的小型 PDF 而言,extraction_timeout_secs: 300远大于实际耗时,tokio::time::timeout正常返回Ok(inner),抽取结果完整保留。这正是契约中两个断言的验证目标:

  • results[0].mime_type == "application/pdf"——格式识别不受超时影响;
  • results[0].content长度不小于 10——正文内容完整返回,没有被截断。

超时只在到期时产生作用:未到期前它是一个纯透明的包裹层,不修改内容、不改变格式识别、不引入额外字段;到期后才以Timeout错误中止该输入。因此把它理解为"保险丝"而不是"节流阀"更准确。

与其他资源限制配置协同

extraction_timeout_secs属于 Xberg 抽取安全配置体系的一部分,建议与以下配置一起使用(均位于ExtractionConfig顶层):

配置字段作用默认值
extraction_timeout_secs单文档最大耗时上限600(秒)
security_limits.max_archive_size压缩包解压总大小上限500 MiB
security_limits.max_compression_ratio压缩比上限(防 ZIP 炸弹)100:1
security_limits.max_files_in_archive压缩包成员文件数上限10,000
security_limits.max_content_size整个文档的文本总量上限100 MB
security_limits.max_iterations解析器迭代次数上限10,000,000
security_limits.max_pagesOCR/布局/渲染的页数上限不限制
max_embedded_file_bytes单个内嵌文件解出大小上限50 MiB

它们各有侧重:字节/大小类限制防御内存膨胀(压缩炸弹、实体扩展),extraction_timeout_secs防御时间消耗(无限循环、超慢路径)。Rust 核心的 配置指南文档 就给出了同时设置security_limits、max_embedded_file_bytes与extraction_timeout_secs的示例,例如对不可信输入收紧为 120 秒。Elixir 中同样可以组合使用:

config = %{ extraction_timeout_secs: 120, security_limits: %{ max_archive_size: 100 * 1024 * 1024, max_files_in_archive: 1_000, max_pages: 250 }, max_embedded_file_bytes: 20 * 1024 * 1024 } Xberg.extract(input: %{kind: "uri", uri: "archive.zip"}, config: config)

平台与目标限制

超时的实际执行依赖可用的 Tokio 定时器。从 core/extractor/bytes.rs 可以看到,在没有tokio-runtime特性或 WASM 目标(std::time::Instant::now()会 panic)上,无法强制执行超时——此时代码只记录一条 debug 日志("extraction_timeout_secs is ignored on this target; running without a timeout")并照常运行抽取,而不会拒绝调用。换句话说:WASM 构建中该字段被接受但被忽略,超时能力仅面向具备运行时定时器的原生目标。如果你在 WASM 或受限目标上依赖超时保护,请额外依靠字节/大小类限制。

小结

  • extraction_timeout_secs是ExtractionConfig顶层字段,类型Option<u64>,默认600秒;
  • Elixir 中通过 JSON 配置传入Xberg.extract/2或Xberg.extract_batch/2即可生效;
  • 它对快速抽取完全透明(不修改结果),到期才中止输入并返回类型化的Timeout错误;
  • 底层由tokio::time::timeout加CancellationToken协同取消实现,且在批处理、REST 异步作业路径均有对应机制;
  • WASM / 无 Tokio 定时器的目标上该字段被接受但忽略,需配合security_limits等大小类限制兜底。

相关代码与文档可在仓库中继续深入:配置结构、字节抽取超时实现、批处理超时实现、Elixir 封装、抽取指南、契约 JSON。

  • 后端
  • AI 应用
  • NLP

【免费下载链接】xberg

Polyglot document intelligence with a Rust core: extract text, metadata, images, tables, and structured data from 106 formats across 140 file extensions, plus code intelligence for 371 languages. Fifteen bindings, with CLI, REST API, and MCP server.

项目地址:https://gitcode.com/gh_mirrors/kr/xberg
点击查看免费下载
上一篇:Vue3前端工程化实践:现代化管理界面开发
下一篇:【限时体验】 JeecgBoot v3.7.3深度集成DeepSeek大模型的技术解析

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询