Dagger TypeScript SDK 错误处理详解:ExecError 类的属性、源码与实战捕获
2026/9/16 12:46:26 网站建设 项目流程

Dagger TypeScript SDK 错误处理详解:ExecError 类的属性、源码与实战捕获

【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger

本篇技术指南以 Dagger TypeScript SDK 中ExecError类(API 参考见 ExecError.md)为核心,介绍当容器流水线(pipeline)中的exec操作失败时,SDK 如何把底层命令退出信息包装成可编程处理的错误对象。读完本文,你将掌握ExecError的全部属性语义、错误码D109的含义、SDK 内部抛出该错误的底层机制,以及如何在 TypeScript 项目中精准捕获并诊断容器命令执行失败。

ExecError 是什么:流水线 exec 操作的 API 错误

在 Dagger 中,构建、测试、发布任何代码库的核心动作大多是对容器执行命令(withExec),当某个容器命令以非零退出码结束,Dagger 引擎会将其标记为EXEC_ERROR类型,Dagger TypeScript SDK 在收到该 GraphQL 响应后会抛出ExecError

从类型体系上看,ExecError直接继承自抽象基类DaggerSDKError,后者是所有 Dagger 错误的父类:

  • 基类定义了namecode两个抽象只读属性,要求每个子类提供 Dagger 专属的错误名称与错误码;
  • 基类持有cause(引发错误的原始 Error)、messagestack
  • 基类还提供printStackTrace()方法用于将堆栈打印到控制台(源码见 DaggerSDKError.ts)。

ExecError的定义位于 ExecError.ts,其类签名与构造函数如下:

export class ExecError extends DaggerSDKError { name = ERROR_NAMES.ExecError code = ERROR_CODES.ExecError cmd: string[] exitCode: number stdout: string stderr: string extensions?: GraphQLErrorExtensions constructor(message: string, options: ExecErrorOptions) { super(message, options) this.cmd = options.cmd this.exitCode = options.exitCode this.stdout = options.stdout this.stderr = options.stderr this.extensions = options.extensions } }

其中ExecErrorOptionsDaggerSDKErrorOptions(仅含cause)基础上,要求调用方必须提供cmdexitCodestdoutstderr,并可附带 GraphQL 扩展信息extensions

属性全解:从命令到输出的完整诊断信息

ExecError携带了排障所需的全部现场信息,每个字段都与一次失败的 exec 操作一一对应。

cmd:导致错误的命令

cmd: string[]

以字符串数组形式保存触发出错的完整命令及其参数,例如["sh", "-c", "cat /testout >&1; cat /testerr >&2; exit 127"]。注意它是参数数组而非拼接好的单行字符串,便于你直接在错误处理中重建命令或做日志脱敏。

exitCode:命令退出码

exitCode: number

容器内命令的退出码。非零退出码(如127表示命令不存在、1表示通用运行失败)是 exec 报错的直接原因。在 SDK 内部,当引擎未提供该字段时会回退为-1

stdout 与 stderr:标准输出与标准错误

stdout: string stderr: string

命令执行期间产生的标准输出与标准错误内容,是定位问题最直接的日志来源。在 SDK 实现中,若引擎未返回对应字段,会回退为空字符串""

值得注意的一个细节:stdout/stderr不会混入message,测试用例专门断言了e.toString()e.message均不包含 stdout/stderr 内容(见 api.spec.ts),因此你可以安全地把message作为简短摘要展示,而把完整输出单独记录。

extensions:GraphQL 错误扩展信息

extensions?: any

透传 GraphQL 响应中附带的extensions对象。SDK 正是通过其中的_type === "EXEC_ERROR"来识别 exec 失败并构造ExecError的(详见下文“源码机制”一节)。

name、code、cause、message、stack

属性类型说明来源
name"ExecError"Dagger 错误名称,值来自ERROR_NAMES.ExecError覆盖基类
code"D109"Dagger 专属错误码,值来自ERROR_CODES.ExecError覆盖基类
causeError(可选)引发错误的原始 Error 对象继承自DaggerSDKError
messagestring错误摘要信息继承自Error
stackstring(可选)调用堆栈继承自Error

方法:printStackTrace()

printStackTrace(): void

继承自DaggerSDKError,调用内部日志工具打印this.stack(见 DaggerSDKError.ts),适合在 catch 分支中快速输出堆栈定位调用链。

错误码体系:D109 在整个 Dagger 错误表中的位置

Dagger TypeScript SDK 为每一类错误分配了稳定的字符串错误码,便于程序化区分错误类型,统一定义在 errors-codes.ts:

错误码错误类
D100GraphQLRequestError
D101UnknownDaggerError
D102TooManyNestedObjectsError
D103EngineSessionConnectParamsParseError
D104EngineSessionConnectionTimeoutError
D105EngineSessionError
D106InitEngineSessionBinaryError
D107DockerImageRefValidationError
D108NotAwaitedRequestError
D109ExecError
D110IntrospectionError

ExecErrornamecode均在类初始化时通过ERROR_NAMES.ExecErrorERROR_CODES.ExecError赋值,因此每个实例天然携带D109标识。所有错误类统一从 index.ts 导出,你可以用以下方式按错误码或错误类型做分支处理:

import { ExecError, ERROR_CODES } from "@dagger.io/dagger" catch (e) { if (e instanceof ExecError) { console.error(`Dagger exec failed with code ${e.code}`) // "D109" } // 或按错误码判断 if ((e as any).code === ERROR_CODES.ExecError) { /* ... */ } }

源码机制:ExecError 是在哪里被抛出的

ExecError并非在容器执行现场直接抛出,而是由 SDK 的 GraphQL 查询层在收到引擎错误响应后统一构造。关键调用链位于 compute_query.ts 的compute函数:

} catch (e: any) { if (e instanceof ClientError) { const msg = e.response.errors?.[0]?.message ?? `API Error` const ext = e.response.errors?.[0]?.extensions if (ext?._type === "EXEC_ERROR") { throw new ExecError(msg, { cmd: (ext.cmd as string[]) ?? [], exitCode: (ext.exitCode as number) ?? -1, stdout: (ext.stdout as string) ?? "", stderr: (ext.stderr as string) ?? "", extensions: ext, }) } throw new GraphQLRequestError(msg, { error: e, cause: e }) } // ... }

机制要点:

  1. SDK 通过 GraphQL 客户端请求引擎,若返回ClientError,则读取首个 GraphQL error 的messageextensions
  2. extensions._type === "EXEC_ERROR"时,从扩展字段中提取cmdexitCodestdoutstderr并构造ExecError抛出——这就是实例属性与 GraphQL 扩展字段的对应来源;
  3. 若错误类型不是 exec 失败,则回退抛出GraphQLRequestError;连接被拒(ECONNREFUSED)时抛出NotAwaitedRequestError(提示函数未被await);其余情况抛出UnknownDaggerError

这一设计意味着:凡是容器内命令执行失败(例如withExec后调用sync()),你捕获到的几乎都是ExecError,且其cmdexitCodestdoutstderr字段与引擎返回一一对应。

实战捕获:从测试用例看正确的处理姿势

官方测试 api.spec.ts 中“Return custom ExecError”用例演示了完整的触发与校验流程:

const stdout = "STDOUT HERE" const stderr = "STDERR HERE" const args = ["sh", "-c", "cat /testout >&1; cat /testerr >&2; exit 127"] await connect(async (client: Client) => { const ctr = client .container() .from("alpine:3.16.2") .withDirectory("/", client.directory() .withNewFile("testout", stdout) .withNewFile("testerr", stderr)) .withExec(args) try { await ctr.sync() } catch (e) { if (e instanceof ExecError) { assert(e.message.includes("exit code: 127")) assert.strictEqual(e.exitCode, 127) assert.strictEqual(e.stdout, stdout) assert.strictEqual(e.stderr, stderr) assert(!e.toString().includes(stdout)) assert(!e.message.includes(stderr)) } else { throw e } } })

由该用例可提炼出三条实战经验:

  • 捕获方式:优先使用e instanceof ExecError做类型守卫,避免用any断言丢失类型信息;sync()是触发容器真正执行的入口,错误在此处抛出;
  • 信息一致性exitCodestdoutstderr与容器内真实行为完全一致,可直接作为 CI 失败诊断的依据;message中会包含类似exit code: 127的摘要,但不会混入完整 stdout/stderr,适合展示给用户;
  • 未命中的兜底:如果 exec 失败但捕获到的不是ExecError(例如请求层异常),应重新抛出或记录原始错误,避免吞掉异常。

另一个用例(Support container sync)则验证了assert.rejects(base.withExec(["foobar"]).sync(), ExecError),说明即使是很短的命令(如不存在的foobar)也会以ExecError形式暴露,捕获路径是稳定一致的。

常见误用与排查建议

  • 在非 await 场景下误判错误类型:如果异步调用未被await,错误可能以NotAwaitedRequestErrorD108)出现而不是ExecError,先检查调用链是否完整await
  • 日志脱敏stdout/stderr可能包含敏感输出,写入日志前按需截断或过滤;cmd是参数数组,注意拼接待执行命令时正确处理含空格参数;
  • 区分错误层级:连接、鉴权、GraphQL 协议类问题会以GraphQLRequestErrorD100)或UnknownDaggerErrorD101)抛出,只有容器内命令真正失败才是ExecErrorD109),据此可设计多级错误处理与重试策略。

ExecError的完整字段与类型签名始终以仓库中的 API 参考文档 ExecError.md、基类文档 DaggerSDKError.md 为准,结合 ExecError.ts 与 compute_query.ts 源码可完整还原其行为。

【免费下载链接】daggerAutomation engine to build, test and ship any codebase. Runs locally, in CI, or directly in the cloud项目地址: https://gitcode.com/GitHub_Trending/da/dagger

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

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

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

立即咨询