news 2026/9/17 19:42:45

Dagger TypeScript SDK 中的 Error 对象:从 GraphQL 错误传播到结构化扩展值的完整指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dagger TypeScript SDK 中的 Error 对象:从 GraphQL 错误传播到结构化扩展值的完整指南

Dagger TypeScript SDK 中的 Error 对象:从 GraphQL 错误传播到结构化扩展值的完整指南

【免费下载链接】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 是一个自动化引擎,用于构建、测试和交付任意代码库。在 Dagger 的 TypeScript SDK(@dagger.io/dagger)中,Error是一个特殊的客户端类:它并非普通 JS 的Error,而是映射到引擎 GraphQL 核心类型Error的懒求值对象,用于在 Dagger 调用链中以结构化方式承载错误消息与可机读的扩展值(key/value 扩展)。本文将基于 Dagger v0.21 TypeScript SDK 的官方 API 参考(见 Error.md),逐方法解析Error类与配套的ErrorValue类的用法,并深入 core/error.go 与 core/schema/error.go 的源码实现,帮助你理解错误对象在 Dagger 引擎中的真实行为,从而在自己的 Dagger 模块中正确创建、扩展和读取错误。

类定义与继承关系

Error类在 TypeScript SDK 中定义于 sdk/typescript/src/api/client.gen.ts,其类型声明位于:

Extends: BaseClient

所有由 Dagger 代码生成器产出的客户端类(ContainerDirectoryClient等)都继承自内部的BaseClientBaseClient持有 GraphQL 查询构建所需的Context与惰性选择器(Selection),因此Error对象本身只是一个"未执行的查询占位符":当你调用它的message()values()等方法时,才真正向引擎发起 GraphQL 查询并返回结果。这正是 Dagger SDK 一贯的"惰性求值 + 可组合调用链"设计,本类也延续了这一模式。

在 client.gen.ts 中可以看到Error类的真实实现:它维护了_id_message两个私有字段作为本地缓存,当对应字段已被构造函数注入时直接返回,避免多余的引擎往返。

构造函数:仅供内部使用

new Error(ctx?, _id?, _message?): Error

构造函数接收三个可选参数:

参数类型说明
ctx?ContextDagger GraphQL 查询上下文,由 SDK 内部注入
_id?ID该 Error 的唯一标识符,用于selectNode反查对象
_message?string错误描述,注入后message()可免查询直接返回

官方文档明确标注:"Constructor is used for internal usage only, do not create object from it."(构造函数仅供内部使用,请勿自行创建对象)。对应的 TS 源码注释在 client.gen.ts 中完全一致。

在实际代码中你也不需要直接 new 一个Error:正确的创建入口是Client上的工厂方法error(),其签名为:

error = (message: string): Error

对应实现见 client.gen.ts,它通过select("error", { message })构造一个指向 GraphQLerror(message: ...)字段的查询并包装为Error实例。服务端该字段的解析逻辑位于 core/schema/error.go:

func (s *errorSchema) error(ctx context.Context, _ *core.Query, args struct { Message string `doc:"A description of the error."` }) (*core.Error, error) { // We don't want to see these in the UI trace.SpanFromContext(ctx).SetAttributes(attribute.Bool(telemetry.UIInternalAttr, true)) return &core.Error{ Message: args.Message, }, nil }

注意其中的细节:创建Error对象时会在当前 span 上标记UIInternalAttr = true,表示这类对象属于内部实现细节,不应展示在 Dagger UI 中。

实例方法详解

id():获取错误对象的唯一标识

id(): Promise<ID>

返回该 Error 的唯一标识符,类型为ID(一个不透明字符串)。如果构造函数已经注入了_id,则直接返回缓存值;否则执行select("id")查询并返回结果(见 client.gen.ts)。

ID在 Dagger 中承担了"持久化对象句柄"的作用:core.Error实现了dagql.PersistedObjectdagql.PersistedObjectDecoder接口(见 core/error.go),EncodePersistedObjectMessageValues编码为 JSON payload,DecodePersistedObject负责反向还原,因此Error可以像ContainerDirectory一样被序列化后在引擎内传递、跨会话引用。

message():获取错误描述

message(): Promise<string>

"A description of the error."(错误的描述文本)。与id()相同,若构造时已注入_message则直接返回,否则执行select("message")查询。在服务端,Message字段定义于 core/error.go:

type Error struct { Message string `field:"true" doc:"A description of the error."` Values []*ErrorValue `field:"true" doc:"The extensions of the error."` }

values():读取错误的扩展值列表

values(): Promise<ErrorValue[]>

"The extensions of the error."(错误的扩展)。该方法返回ErrorValue对象数组,每个ErrorValue{ name: string; value: JSON }的键值对,用于承载附加的结构化信息。

其生成实现比较有代表性(client.gen.ts):SDK 首先执行select("values").select("id")拿到每个ErrorValue的 ID 列表,随后通过selectNode(r.id, "ErrorValue")为每个 ID 构建独立的懒查询对象——这是 Dagger TS SDK 处理"对象数组字段"的标准手法,最终返回的ErrorValue[]中的每个元素都可以继续链式调用name()value()

with():在不破坏调用链的前提下复用当前对象

with(arg: (param: Error) => Error): Error

"Call the provided function with current Error. This is useful for reusability and readability by not breaking the calling chain."(以当前 Error 调用传入的函数,便于在不打断调用链的前提下实现复用与可读性)。

实现非常简单(client.gen.ts):

with = (arg: (param: Error) => Error) => { return arg(this) }

这是 Dagger 各 SDK 通用的with()模式:把"对当前对象的后续操作"封装进回调函数,返回回调的产物,从而支持类似client.error("...").with(e => e.withValue("code", 42))的可读写法。

withValue():向错误附加结构化扩展值

withValue(name: string, value: JSON): Error
参数类型说明
namestringThe name of the value.(值的名称)
valueJSONThe value to store on the error.(要存储在错误上的值)

返回一个新的Error。注意该方法是"返回新对象"而非原地修改——它通过select("withValue", { name, value })构造一条新的 GraphQL 选择器并包装成新的Error返回(client.gen.ts),这与整个 Dagger API 的不可变/惰性设计一致:每次调用都产生一条新的查询链路,最终由引擎统一求值。

服务端withValue的实现见 core/schema/error.go,它委托给core.Error.WithValue

func (s *errorSchema) withValue(ctx context.Context, self *core.Error, args struct { Name string `doc:"The name of the value."` Value core.JSON `doc:"The value to store on the error."` }) (*core.Error, error) { return self.WithValue(args.Name, args.Value), nil }

core.Error.WithValue采用"克隆后追加"的不可变策略(core/error.go):

func (e *Error) Clone() *Error { cp := *e cp.Values = slices.Clone(e.Values) return &cp } func (e *Error) WithValue(name string, value JSON) *Error { cp := e.Clone() cp.Values = append(cp.Values, &ErrorValue{ Name: name, Value: value, }) return cp }

Values切片被深拷贝后再追加新元素,保证原对象不受影响。

配套类型:ErrorValue

values()返回的元素类型ErrorValue同样继承自BaseClient,包含三个方法:

方法返回类型语义
id()Promise<ID>A unique identifier for this ErrorValue.(唯一标识)
name()Promise<string>The name of the value.(值的名称)
value()Promise<JSON>The value.(值本体,类型为 JSON)

服务端ErrorValuecore/error.go中一个精简的持久化对象(core/error.go):

type ErrorValue struct { Name string `field:"true" doc:"The name of the value."` Value JSON `field:"true" doc:"The value."` }

JSON是 Dagger 对任意 JSON 值的封装类型,因此withValue的第二个参数可以传入对象、数组、字符串、数字等任意可 JSON 序列化的数据,使得错误不仅能携带人类可读的message,还能附带"错误码、失败步骤、重试建议、结构化上下文"等供程序消费的数据。

底层原理:Error 如何参与 Dagger 的错误传播

理解Error客户端对象的最佳方式,是看它如何在引擎内部与 Go 的error体系打通。

core.Error同时实现了两个 Go 接口(core/error.go):

var _ error = (*Error)(nil) func (e *Error) Error() string { return e.Message } var _ dagql.ExtendedError = (*Error)(nil) func (e *Error) Extensions() map[string]any { ext := map[string]any{} for _, v := range e.Values { var val any json.Unmarshal(v.Value, &val) ext[v.Name] = val } return ext }

这意味着:任何返回*core.Error的解析器同时也是一个标准error(其Error()返回Message),且它的Values会被映射为 GraphQL 错误扩展字段(extensions)——这正好与values()在文档中的描述 "The extensions of the error" 遥相呼应。

更关键的是转换函数NewErrorFromErr(core/error.go):当引擎需要把一个任意 Go error 包装成可返回给客户端的Error对象时,它会检查该 error 是否实现了dagql.ExtendedError接口:

  • 若实现了,则通过error(message: ...)字段创建Error,并按 key 排序后逐个调用withValue(name, value)Extensions()中的全部键值对附加进去;
  • 若未实现,则仅用error(message: fromErr.Error())创建只有messageError

这一转换由CurrentDagqlServer(ctx).Select在服务端执行,最终以 GraphQL 选择器序列的形式完成,与你用 TS SDK 手工构造的调用链在语义上完全等价。可以推断:当你在模块函数中抛出错误时,Dagger 引擎会借助类似机制将错误"投影"为 GraphQLError对象,使得错误信息能够以结构化的方式跨越引擎边界、出现在调用方的values()中。

完整使用示例

综合以上内容,一个典型的 TypeScript SDK 使用场景如下:

import { dag } from "@dagger.io/dagger" // 通过 Client 工厂方法创建 Error(不要直接 new Error) const err = dag .error("build failed") .withValue("stage", "compile") .withValue("exitCode", 1) // 惰性求值:真正执行时才发起 GraphQL 查询 const message = await err.message() const values = await err.values() for (const v of values) { console.log(await v.name(), await v.value()) } // with() 让复用和组合更简洁 const decorated = err.with((e) => e.withValue("retryable", false))

需要再次强调的是:

  • 创建:使用dag.error(message)(对应 client.gen.ts),构造函数仅供 SDK 内部使用;
  • 惰性Error是查询占位符,字段方法在被await时才执行 GraphQL 查询(部分字段命中本地缓存时免查询);
  • 不可变withValue()返回新对象,原Error不受影响,适合构建可复用的错误模板;
  • 扩展values()读取的即 GraphQLextensions,与core.Error.Extensions()的双向映射保持一致,见 core/error.go。

补充说明与适用前提

本文基于仓库中version-0.21版本化文档目录下的 Error.md 及其关联的 ErrorValue.md。该页面是 SDK 自动生成的 API 参考的一部分,完整索引见 client.gen 参考首页;当前仓库主版本对应的 TS SDK 生成源码可在 sdk/typescript/src/api/client.gen.ts 中查阅,核心类型定义与 GraphQL 解析器分别在 core/error.go 与 core/schema/error.go 中。若你使用的 Dagger 版本不同,方法签名与行为可能有所差异,请以你所安装版本的 SDK 生成代码与文档为准。

【免费下载链接】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),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/17 19:42:36

agent-skills设计实战:打造稳定可靠的智能体技能库

这些年做大模型应用&#xff0c;我越来越觉得“agent-skills”这个说法比“prompt engineering”更贴近真实战场。模型本身的能力边界其实很清晰&#xff0c;真正让一个智能体从“能聊天”变成“能干活”的&#xff0c;是它手里到底攒了多少个设计扎实、边界清楚、可复用、可观…

作者头像 李华
网站建设 2026/9/17 19:39:49

元器件可靠性降额准则一览:从应力模型到选型校验实践

简介&#xff1a;元器件可靠性降额准则一览表面向电子设计与可靠性工程师&#xff0c;聚焦新能源、汽车电子、检测技术等领域&#xff0c;解决元器件可靠性设计与降额选型中的实际问题。文档系统梳理降额&#xff08;derating&#xff09;、额定值、应力比等基本概念&#xff0…

作者头像 李华
网站建设 2026/9/17 19:38:33

C#脚本引擎选型指南:Flee与AScript对比及工控热更新实践

前年冬天在热处理车间调一套上位机&#xff0c;工艺参数表三天一小改、五天一改&#xff0c;每次改完都要重新编译发布&#xff0c;现场停线等我们装包&#xff0c;那滋味真不好受。也就是从那时候起&#xff0c;我开始认真琢磨C# 脚本引擎这件事——让公式、规则、判定逻辑从硬…

作者头像 李华
网站建设 2026/9/17 19:36:06

C语言能力校准器:从练习册答案反推标准代码

简介&#xff1a;本资源是南京林业大学《C语言程序设计》配套练习册的完整参考答案&#xff0c;专为该校及相关高校C语言初学者设计&#xff0c;用于辅助课后练习、考前复习与编程能力自查。答案覆盖全部八章核心内容&#xff1a;数据类型与表达式、输入输出、选择与循环结构、…

作者头像 李华