跳转到内容
getnextpdf.com

运行时与支持错误

这些条目记录由运行时支持层抛出的异常: 降级策略、基于 cURL 的 HTTP 传输、弹性断路器、Security Information and Event Management(SIEM)发送器、 渲染清单、PDF 检查,以及混沌工程子系统。

每个 NextPDF 异常都继承 NextPdfException,后者实现了 ContextAwareExceptionInterface 并暴露 getContext(): array 以进行结构化诊断日志记录。一个子类只有在它重写 getContext() 时才会填充那个数组;基类返回一个空数组。本页上有三个异常(DegradedExceptionCircuitBreakerOpenExceptionInspectException)直接继承 PHP 的 RuntimeException,并通过公开的 readonly 属性而非 getContext() 暴露其数据。下文每个条目都会指明该类携带的确切属性或上下文键,取自源代码。

  • Thrown when. 渲染流水线遇到一个违反激活的降级策略的降级能力时。在 DegradationPolicy::Strict 下,任何高影响降级 (ComplianceRiskSemanticLossBlocking)都会抛出它;在 DegradationPolicy::Balanced 下,只有 Blocking 影响才会抛出它。
  • Class. 直接继承 RuntimeException(而非 NextPdfException),因此它不携带 getContext()
  • Data carried. 两个公开的 readonly 属性:$capability(触发该拒绝的 Capability 值对象,包括它的 idstatusreasonfallbackTargetimpact)和 $policy(拒绝时激活的 DegradationPolicy)。消息的形式为 Feature "<id>" is <status>: <reason> (policy: <policy>)
  • Recovery. 检查 $capability 以识别缺失的特性及其原因。要么安装该能力所需的组件、接受一个更低影响的配置,要么在该降级对用例可接受时把策略从 Strict 放宽到 Balanced。调用 $capability->isAvailable() / isDegraded() 来驱动面向用户的消息提示。

这三个异常源于基于 cURL 的 PSR-18 客户端及其安全感知装饰器。前两个继承 NextPdfException,但不重写 getContext(),因此它们的 getContext() 返回一个空数组; 诊断数据可经由 PSR-18 getRequest() 访问器和链接的前一个 throwable 触及。

  • Thrown when. HTTP 请求因一个网络级故障而无法完成:Domain Name System(DNS)解析失败、 连接超时,或 Transport Layer Security(TLS)握手错误。它也是安全感知装饰器为一次安全拒绝 (服务器端请求伪造拒绝、DNS 重绑定拒绝,或一次被拒的重定向)所抛出的类。
  • Class. 实现 PSR-18 Psr\Http\Client\NetworkExceptionInterface
  • Data carried. getRequest() 返回失败的 RequestInterface。 发起的传输错误(如果存在)是链接的前一个 throwable。getContext() 返回一个空数组(基类默认)。
  • Recovery. 一个网络故障可能是瞬时的——如果请求是幂等的,请用退避重试。一次安全拒绝不是瞬时的,且必须失败即关闭:不要重试;而应纠正目标 URL 或 SSRF 策略。 阅读消息和前一个 throwable 来区分二者。
  • Thrown when. 请求本身因格式错误而无法被发送, 例如一个无效的 URL,或一个在任何网络调用之前就未通过 SSRF 验证的请求。
  • Class. 实现 PSR-18 Psr\Http\Client\RequestExceptionInterface
  • Data carried. getRequest() 返回出问题的 RequestInterface; 底层原因(如果存在)是链接的前一个 throwable。 getContext() 返回一个空数组。
  • Recovery. 这是一个调用方输入或策略缺陷,而非一个瞬时故障。不要原样重试。修正请求 URL、头部或正文,或在目标确实被合法允许时调整 SSRF 允许列表,然后重新发出请求。
  • Thrown when. 在内部,于 SecurityAwareHttpClient 内,把一个真正瞬时的内层传输故障(由内层 PSR-18 客户端抛出的 DNS、连接或超时)标记为有资格进入那个有界的重试预算。 它是装饰器的重试循环所识别的唯一有资格重试的类; 一个未被包装的异常(一次由装饰器抛出的安全拒绝)会被当作致命来处理。
  • Class. 实现 PSR-18 Psr\Http\Client\NetworkExceptionInterface。 标记为 @internal——它完全在 SecurityAwareHttpClient 内被创建和解包,绝不会逃逸出装饰器。
  • Data carried. getRequest() 返回失败的请求。原始的内层传输 ClientExceptionInterface 被保留为链接的前一个 throwable(getPrevious()),并在重试预算耗尽后被原封不动地重新浮现给调用方,因此公开的 PSR-18 契约保持不变。getContext() 返回一个空数组。
  • Recovery. 应用代码不会直接捕获这个类型。请捕获装饰器在重试预算耗尽后返回的、被重新浮现的内层异常,并把反复的瞬时失败当作一个上游可用性问题来处理。
  • Thrown when. 一个处于 CircuitBreakerState::Open 状态的 CircuitBreaker 在任何下游调用之前就快速失败地拒绝一次调用。它的存在是为了让调用方区分“远程服务此刻不可达”(一个瞬时的、值得降级的传输故障)与“连接池本会被这次调用耗尽”(快速失败,未尝试任何网络)—— 这是 Public Key Infrastructure(PKI)客户端所需的批量拒绝服务缓解措施。
  • Class. 直接继承 RuntimeException,因此它不携带 getContext()
  • Data carried. 两个公开的 readonly 属性:$breakerName(打开的断路器的标识符)和 $secondsUntilHalfOpen(断路器转入半开之前剩余的近似冷却时间)。消息的形式为 Circuit breaker "<name>" is OPEN (cooldown ~<n>s remaining); call rejected fail-fast.
  • Recovery. 不要猛击该断路器——在重试之前至少等待 $secondsUntilHalfOpen,或降级该操作。没有网络调用被尝试,因此这并不能证明远程服务本身失败了;它是保护连接池的背压。
  • Thrown when. 一个 SIEM 事件发送器无法持久化或链接一条记录。它会浮现文件系统级的失败(openlockseekwritefflushread)和哈希链完整性故障(chain:乱序索引、格式错误的尾部记录,或 JSON 往返漂移),这些在哈希链事件日志和 JSON-lines 文件写出器适配器之间共享。
  • Class. 继承 NextPdfException 并重写 getContext()
  • Context keys. operationopenlockseekwritefflushreadchain 之一)、path(目标日志路径),以及 detail(一段人类可读的细节,例如字节数或期望与实际的索引)。 这些也可经由 getOperation()getPath()getDetail() 触及。消息的形式为 SIEM emitter <operation> failed for <path>: <detail>.
  • Recovery. 这可由基础设施或 SecOps 操作,而非由应用逻辑。核实日志卷挂载、目录权限、 可用文件描述符,以及文件系统健康状况。一次 chain 操作失败表明审计日志中存在篡改或损坏信号,应当被调查,而非静默地重试。
  • Thrown when. 一个 RenderManifest 因某个结构、类型或 schema 兼容性错误而无法被构造、反序列化或读取。该清单是一份由每个传输(CLI、 Laravel 队列、Symfony、SaaS API)提交的版本化公开契约,因此一份格式错误或不兼容的清单会被直接浮现,而非被强制转换为默认值。
  • Class. 继承 NextPdfException 并重写 getContext()。具名构造函数会在 SPEC-MANIFEST-* 命名空间中设置一个稳定的、机器可读的代码:
    • RenderManifestException::shape()SPEC-MANIFEST-001 — 在 RenderManifest::fromArray() 期间的形态或类型错误。
    • RenderManifestException::incompatibleVersion()SPEC-MANIFEST-002 — 不兼容的主版本 schema 版本(无法被读取)。
    • RenderManifestException::missingField()SPEC-MANIFEST-003 — 在 builder 最终化期间缺少必填字段。
    • RenderManifestException::unsupported()SPEC-MANIFEST-004 — 一份良构的清单引用了一个当前渲染器无法解析的输入或模板 (例如一个 URI 输入或一个仅限主机的模板引擎)。
  • Context keys. manifest_codeSPEC-MANIFEST-* 标识符)和 reason(人类可读的失败描述)。这些也可经由 getManifestCode()getReason() 触及。消息的形式为 [<code>] <reason>
  • Recovery.manifest_code 上分支。对于 SPEC-MANIFEST-001SPEC-MANIFEST-003,修正清单负载(纠正字段类型或提供缺失的字段)。对于 SPEC-MANIFEST-002,针对一个受支持的主版本 schema 版本重新生成清单,或升级渲染器。对于 SPEC-MANIFEST-004,提供一个当前版本能解析的输入或模板引擎。
  • Thrown when. PDF 检查失败。
  • Class. 直接继承 RuntimeException(而非 NextPdfException),因此它不携带 getContext()
  • Data carried. 两个公开的 readonly 属性:$inspectCode(一个在 INSPECT-* 命名空间中的机器可读代码)和 $retryable(一个布尔值,指示调用方是否应当重试——例如当一个检查边车暂时宕机时)。发起的原因(如果存在)是链接的前一个 throwable。
  • Recovery.$inspectCode 上分支以确定具体的失败类别。当 $retryabletrue 时,用退避重试,因为该失败被预期是瞬时的(例如一次边车重启);当为 false 时,把输入或配置当作缺陷来处理,并且不要原样重试。
  • Thrown when. ChaosScenarioRunner::writeReport() 无法把聚合的混沌日报告持久化到磁盘。它是一个对通用运行时错误的领域类型化替代品,以便调用方可以捕获那个具体的报告磁盘失败, 而不会把它与场景模拟器本身内部抛出的错误混为一谈(runner 会把那些捕获为 ChaosOutcome 字段)。
  • Class. 继承 NextPdfException 并重写 getContext()
  • Context keys. output_path(runner 尝试写入的绝对路径)。 它也可经由 getOutputPath() 触及。消息的形式为 ChaosScenarioRunner: failed to write report to "<path>".
  • Recovery. 这是报告接收端的写入侧失败,而非场景的失败。核实输出目录存在且可写,并且磁盘空间可用,然后重新运行报告写入。混沌结果本身不受影响。
  • Thrown when. 一个检索端点(例如一个 Voyage Retrieval Augmented Generation 服务)不可用,且系统要么回退到仅缓存模式,要么失败即关闭。
  • Class. 继承 NextPdfException 并重写 getContext()
  • Context keys. mode(失败之后的运行模式—— 当结果仅从语义缓存提供时为 CACHED_ONLY,或当请求被完全拒绝且没有任何陈旧数据时为 FAIL_CLOSED)和 endpoint(变得不可达的那个端点)。这些也可经由 getMode()getEndpoint() 触及。消息的形式为 Retrieval endpoint "<endpoint>" is unavailable; operating in <mode> mode.
  • Recovery. 阅读 mode 以了解系统如何降级。在 CACHED_ONLY 下,结果可能是陈旧的;一旦端点恢复就刷新。 在 FAIL_CLOSED 下,请求按设计被拒绝,且必须在端点可达之后重试。在依赖新鲜检索之前,恢复端点连通性(网络、凭证、服务健康)。