跳到內容
getnextpdf.com

執行階段與支援錯誤

下列條目記錄由執行階段支援層所拋出的例外狀況:降級政策、以 cURL 為後盾的 HTTP 傳輸、韌性斷路器、Security Information and Event Management(SIEM)發送器、render manifest、PDF 檢查,以及混沌工程子系統。

每個 NextPDF 例外狀況都繼承 NextPdfException,後者實作 ContextAwareExceptionInterface 並揭露 getContext(): array 以供結構化的診斷記錄使用。子類別只有在覆寫 getContext() 時才會填充該陣列;基底類別回傳空陣列。本頁有三個例外狀況(DegradedExceptionCircuitBreakerOpenExceptionInspectException)直接繼承 PHP 的 RuntimeException,並以公開的 readonly 屬性揭露其資料,而非 getContext()。下方每個條目都會具名說明該類別所攜帶的確切屬性或脈絡鍵,取自原始碼。

  • 何時被拋出。 當繪製管線遇到一項違反當前降級政策的降級能力時。在 DegradationPolicy::Strict 下,任何高影響降級(ComplianceRiskSemanticLossBlocking)都會將它拋出;在 DegradationPolicy::Balanced 下,只有 Blocking 影響才會將它拋出。
  • 類別。 直接繼承 RuntimeException(而非 NextPdfException),因此它不攜帶 getContext()
  • 攜帶的資料。 兩個公開的 readonly 屬性:$capability(觸發拒絕的 Capability 值物件,包含其 idstatusreasonfallbackTargetimpact)與 $policy(拒絕當下生效的 DegradationPolicy)。訊息的格式為 Feature "<id>" is <status>: <reason> (policy: <policy>)
  • 解法。 檢視 $capability 以辨識缺少的功能及其成因。可安裝該能力所需的元件、接受影響較低的組態,或在該降級對使用情境而言可接受時,將政策從 Strict 放寬為 Balanced。呼叫 $capability->isAvailable() / isDegraded() 來驅動面向使用者的訊息。

這三個例外狀況源自以 cURL 為後盾的 PSR-18 用戶端及其具安全意識的裝飾器。前兩者繼承 NextPdfException,但未覆寫 getContext(),因此其 getContext() 回傳空陣列;診斷資料可透過 PSR-18 的 getRequest() 存取器與鏈結的前一個 throwable 取得。

  • 何時被拋出。 當 HTTP 請求因網路層級的故障而無法完成時:Domain Name System(DNS)解析失敗、連線逾時,或 Transport Layer Security(TLS)交握錯誤。它也是具安全意識的裝飾器在安全拒絕(拒絕 Server-Side Request Forgery、拒絕 DNS-rebinding,或遭拒的重新導向)時所拋出的類別。
  • 類別。 實作 PSR-18 Psr\Http\Client\NetworkExceptionInterface
  • 攜帶的資料。 getRequest() 回傳失敗的 RequestInterface。源頭的傳輸錯誤若存在,會是鏈結的前一個 throwable。getContext() 回傳空陣列(基底預設值)。
  • 解法。 網路故障可能是暫時性的——若請求具冪等性,可採退避重試。安全拒絕並非暫時性,且必須失敗即關閉:不要重試;應改為更正目標 URL 或 SSRF 政策。請讀取訊息與前一個 throwable 來分辨兩者。
  • 何時被拋出。 當請求本身因為格式錯誤而無法送出時,例如無效的 URL,或一個在任何網路呼叫之前就未通過 SSRF 驗證的請求。
  • 類別。 實作 PSR-18 Psr\Http\Client\RequestExceptionInterface
  • 攜帶的資料。 getRequest() 回傳出問題的 RequestInterface;底層成因若存在,會是鏈結的前一個 throwable。getContext() 回傳空陣列。
  • 解法。 這是呼叫端輸入或政策的缺陷,而非暫時性故障。不要原封不動地重試。請修正請求的 URL、標頭或主體,或在目標確屬合法允許時調整 SSRF 允許清單,然後重新發出請求。
  • 何時被拋出。 於內部,在 SecurityAwareHttpClient 中,用來把一個真正暫時性的內層傳輸故障(由內層 PSR-18 用戶端引發的 DNS、連線或逾時)標記為符合有界重試預算的資格。它是裝飾器的重試迴圈唯一認得的可重試類別;未經包裝的例外狀況(裝飾器引發的安全拒絕)會被視為致命。
  • 類別。 實作 PSR-18 Psr\Http\Client\NetworkExceptionInterface。標記為 @internal——它完全在 SecurityAwareHttpClient 內被建立與解包,絕不逸出裝飾器。
  • 攜帶的資料。 getRequest() 回傳失敗的請求。原本的內層傳輸 ClientExceptionInterface 會被保留為鏈結的前一個 throwable(getPrevious()),並在重試預算用盡後原封不動地重新浮現給呼叫端,因此公開的 PSR-18 合約維持不變。getContext() 回傳空陣列。
  • 解法。 應用程式碼不會直接攔截此型別。請攔截裝飾器在重試預算耗盡後回傳的、重新浮現的內層例外狀況,並把反覆的暫時性失敗視為上游的可用性問題。
  • 何時被拋出。 當處於 CircuitBreakerState::Open 狀態的 CircuitBreaker 在任何下游呼叫之前就快速失敗地拒絕一次呼叫時。它的存在是為了讓呼叫端能區分「遠端服務目前無法連線」(一個暫時性的傳輸故障,值得降級)與「這次呼叫本會耗盡連線池」(快速失敗,未嘗試任何網路)——這是 Public Key Infrastructure(PKI)用戶端所要求的批次拒絕服務緩解措施。
  • 類別。 直接繼承 RuntimeException,因此它不攜帶 getContext()
  • 攜帶的資料。 兩個公開的 readonly 屬性:$breakerName(開啟的斷路器的識別碼)與 $secondsUntilHalfOpen(斷路器轉為半開之前所剩的概略冷卻時間)。訊息的格式為 Circuit breaker "<name>" is OPEN (cooldown ~<n>s remaining); call rejected fail-fast.
  • 解法。 不要猛敲斷路器——在重試前至少等待 $secondsUntilHalfOpen,或將該操作降級。並未嘗試任何網路呼叫,因此這不是遠端服務本身失敗的證據;它是保護連線池的反壓。
  • 何時被拋出。 當 SIEM 事件發送器無法持久化或鏈結一筆記錄時。它揭露檔案系統層級的失敗(openlockseekwritefflushread)與雜湊鏈完整性故障(chain:索引順序錯亂、尾端記錄格式錯誤,或 JSON 來回轉換漂移),這些是雜湊鏈事件日誌與 JSON-lines 檔案發送器轉接器所共用的。
  • 類別。 繼承 NextPdfException 並覆寫 getContext()
  • 脈絡鍵。 operationopenlockseekwritefflushreadchain 之一)、path(目標日誌路徑)與 detail(人類可讀的細節,例如位元組數或預期對實際的索引)。這些也可透過 getOperation()getPath()getDetail() 取得。訊息的格式為 SIEM emitter <operation> failed for <path>: <detail>.
  • 解法。 這由基礎設施或 SecOps 處理,而非應用程式邏輯。請查驗日誌磁碟的掛載、目錄權限、可用的檔案描述符,以及檔案系統健康狀態。chain 操作失敗代表稽核日誌中有竄改或損毀的訊號,應加以調查,而非悄悄重試。
  • 何時被拋出。RenderManifest 因結構性、型別或結構描述相容性錯誤而無法建構、反序列化或讀取時。manifest 是一份具版本的公開合約,由每個傳輸(CLI、Laravel 佇列、Symfony、SaaS API)提交,因此格式錯誤或不相容的 manifest 會被直接揭露,而非強行套用預設值。
  • 類別。 繼承 NextPdfException 並覆寫 getContext()。具名建構式會在 SPEC-MANIFEST-* 命名空間中設定一個穩定的機器可讀代碼:
    • RenderManifestException::shape()SPEC-MANIFEST-001RenderManifest::fromArray() 期間的形狀或型別錯誤。
    • RenderManifestException::incompatibleVersion()SPEC-MANIFEST-002 — 不相容的主要結構描述版本(無法讀取)。
    • RenderManifestException::missingField()SPEC-MANIFEST-003 — 建構器最終化期間缺少必填欄位。
    • RenderManifestException::unsupported()SPEC-MANIFEST-004 — 一個格式正確的 manifest 參照了當前繪製器無法解析的輸入或範本(例如 URI 輸入或僅限主機的範本引擎)。
  • 脈絡鍵。 manifest_codeSPEC-MANIFEST-* 識別碼)與 reason(人類可讀的失敗描述)。這些也可透過 getManifestCode()getReason() 取得。訊息的格式為 [<code>] <reason>
  • 解法。manifest_code 分支處理。對於 SPEC-MANIFEST-001SPEC-MANIFEST-003,修正 manifest 酬載(更正欄位型別或補上缺少的欄位)。對於 SPEC-MANIFEST-002,針對受支援的主要結構描述版本重新產生 manifest,或升級繪製器。對於 SPEC-MANIFEST-004,提供當前版本能解析的輸入或範本引擎。
  • 何時被拋出。 當 PDF 檢查失敗時。
  • 類別。 直接繼承 RuntimeException(而非 NextPdfException),因此它不攜帶 getContext()
  • 攜帶的資料。 兩個公開的 readonly 屬性:$inspectCodeINSPECT-* 命名空間中的機器可讀代碼)與 $retryable(一個布林值,指出呼叫端是否應重試——例如當檢查 sidecar 暫時停擺時)。源頭成因若存在,會是鏈結的前一個 throwable。
  • 解法。$inspectCode 分支處理特定的失敗類別。當 $retryabletrue 時,採退避重試,因為該失敗預期是暫時性的(例如 sidecar 重啟);當為 false 時,把輸入或組態當作缺陷,且不要原封不動地重試。
  • 何時被拋出。ChaosScenarioRunner::writeReport() 無法把彙整後的混沌日報持久化到磁碟時。它是對通用執行階段錯誤的領域具型別替代品,因此呼叫端可攔截特定的「報告磁碟」失敗,而不會把它與情境模擬器本身內部引發的錯誤混為一談(runner 會把那些錯誤擷取為 ChaosOutcome 欄位)。
  • 類別。 繼承 NextPdfException 並覆寫 getContext()
  • 脈絡鍵。 output_path(runner 嘗試寫入的絕對路徑)。它也可透過 getOutputPath() 取得。訊息的格式為 ChaosScenarioRunner: failed to write report to "<path>".
  • 解法。 這是報告接收端的寫入端失敗,而非情境本身的失敗。請查驗輸出目錄存在且可寫入,以及磁碟空間充足,然後重新執行報告寫入。混沌結果本身不受影響。
  • 何時被拋出。 當一個檢索端點(例如 Voyage Retrieval Augmented Generation 服務)不可用,且系統選擇退回到僅快取模式或失敗即關閉時。
  • 類別。 繼承 NextPdfException 並覆寫 getContext()
  • 脈絡鍵。 mode(失敗後的運作模式——當結果僅由語意快取供應時為 CACHED_ONLY,當請求被完全拒絕且無任何陳舊資料時為 FAIL_CLOSED)與 endpoint(變得無法連線的端點)。這些也可透過 getMode()getEndpoint() 取得。訊息的格式為 Retrieval endpoint "<endpoint>" is unavailable; operating in <mode> mode.
  • 解法。 讀取 mode 以了解系統如何降級。在 CACHED_ONLY 下,結果可能陳舊;端點復原後請重新整理一次。在 FAIL_CLOSED 下,請求是依設計被拒絕的,必須在端點可連線後重試。在仰賴新鮮的檢索之前,請先恢復端點連線能力(網路、憑證、服務健康狀態)。