Dagger TypeScript SDK connect 模块解析:connect() 与 connection() 的引擎连接机制
2026/9/17 11:32:24 网站建设 项目流程

Dagger TypeScript SDK connect 模块解析:connect() 与 connection() 的引擎连接机制

【免费下载链接】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

connect 模块是 Dagger TypeScript SDK 的引擎连接入口,它负责启动/接入 Dagger 引擎会话、初始化 GraphQL 客户端,并把可编程的Client对象或全局dag客户端交到你的回调函数中。读完本文,你将掌握connect()connection()两个 API 的完整签名、ConnectOpts全部配置项、底层会话建立链路(自动 provisioning 与DAGGER_SESSION_*直连),并能直接写出可运行的 Dagger TypeScript 流水线。

本文基于仓库中 version-0.20 的 TypeScript 参考文档 展开,并结合 sdk/typescript 目录下的真实源码进行验证与补充。

一、connect 模块在 SDK 中的位置

connect是 @dagger.io/dagger 包内的一个核心子模块,其 API 参考文档位于 reference/typescript/connect,完整模块清单见 modules.md。

从 sdk/typescript/src/index.ts 可以看出,包的公开导出中与连接相关的部分包括:

// Connection for library export type { CallbackFct } from "./connect.js" export { connect, connection } from "./connect.js" export type { ConnectOpts } from "./connectOpts.js" // Export dagger connection context export { Context, BaseClient } from "./common/context.js"

也就是说,一个典型的 Dagger TypeScript 流水线只需要一行导入即可获得全部连接能力:

import { connect } from "@dagger.io/dagger"

connect 模块本身暴露的 API 并不多,参考文档中一共包含一个类型别名和两个函数:

API类型作用
CallbackFctType Aliasconnect()回调函数的签名
connectFunction建立连接并把Client实例传给回调
connectionFunction用全局dag客户端执行回调

二、CallbackFct:connect() 的回调类型

CallbackFct是传给connect()的回调函数类型,其完整定义是:

type CallbackFct = (client: Client) => Promise<void>
  • 参数client:类型为 Client,是经过代码生成(client.gen)的 Dagger GraphQL API 客户端,container()host()directory()git()等一切顶层操作都从它出发。
  • 返回值Promise<void>,回调内部可以await任意 Dagger 操作,返回后连接会话随即被清理。

在 sdk/typescript/src/connect.ts 中,它的声明与文档完全对应:

export type CallbackFct = (client: Client) => Promise<void>

注意:connection()的回调签名与CallbackFct不同——它不接收client参数(详见下文第五节),因此connectconnection在使用形态上有明显差异。

三、connect():显式客户端连接

函数签名

connect(cb: CallbackFct, config?: ConnectOpts): Promise<void>
  • cb:类型为 CallbackFct,接收Client实例。
  • config?:类型为ConnectOpts,默认值{}
  • 返回值:Promise<void>

参考文档对connect的定位描述是:connect runs GraphQL server and initializes a GraphQL client to execute query on it through its callback. This implementation is based on the existing Go SDK.(运行/建立 GraphQL 会话并初始化 GraphQL 客户端,通过回调在它上面执行查询,实现基于既有 Go SDK)。

源码实现解读

sdk/typescript/src/connect.ts 中的实现清晰地展示了它背后的四步动作:

export async function connect( cb: CallbackFct, config: ConnectOpts = {}, ): Promise<void> { await withGQLClient(config, async (gqlClient: GraphQLClient) => { const connection = new Connection(gqlClient) const ctx = new Context([], connection) const client = new Client(ctx) // Warning shall be throw if versions are not compatible try { await client.version() } catch (e) { console.error("failed to check version compatibility:", e) } return await cb(client) }) }
  1. withGQLClient(config, cb):建立(或复用)指向 Dagger 引擎的 GraphQL 连接。这是整个连接机制的枢纽,其内部逻辑在下一节详细展开。
  2. 构造客户端栈new Connection(gqlClient)包装 GraphQL 客户端,new Context([], connection)创建带连接上下文的求值上下文,最后new Client(ctx)生成对外暴露的 Dagger 客户端。
  3. 版本兼容性检查await client.version()会向引擎发起一次 version 查询;如果失败(例如 SDK 与引擎版本不匹配),打印告警failed to check version compatibility但不会中断执行——注意源码注释为Warning shall be throw if versions are not compatible,目前实现为捕获异常并输出到 stderr。
  4. 执行用户回调await cb(client),把初始化完成的Client交给你的业务代码。

典型用法

import { connect } from "@dagger.io/dagger" await connect( async (client) => { const out = await client .container() .from("alpine") .withExec(["echo", "hello from dagger"]) .stdout() console.log(out) }, { LogOutput: process.stderr }, )

四、ConnectOpts:连接配置项全解

ConnectOpts定义于 sdk/typescript/src/connectOpts.ts,注释明确说明其用途:ConnectOpts defines option used to connect to an engine.三个字段及其默认行为如下:

字段类型默认值说明
Workdirstringprocess.cwd()覆盖 Dagger 的工作目录。流水线中client.host().workdir()读取到的就是该目录
LoadWorkspaceModulesbooleanfalse(不开启)是否加载 workspace 模块;默认只暴露核心 API(core API)
LogOutputWritable不输出开启引擎日志输出,需传入 Node.js 可写流(如process.stdout/process.stderr

Workdir:控制宿主工作目录

当你的脚本运行目录与 Dagger 逻辑工作目录不一致时,可以通过Workdir显式指定:

await connect( async (client) => { const entries = await client.host().workdir().entries() console.log(entries) }, { Workdir: "/path/to/my/project" }, )

LoadWorkspaceModules:加载 workspace 模块

默认情况下连接只暴露 Dagger 核心 API。如果你的项目配置了 workspace 模块(例如通过dagger.toml声明了模块依赖),需要把该选项置为true,连接时才会加载这些模块供dag/client调用。

LogOutput:日志流输出

便于在终端直接观察引擎侧日志。源码注释给出了一个完整例子:

connect(async (client: Client) => { const source = await client.host().workdir().id() // ... 其余流水线逻辑 }, { LogOutput: process.stdout })

五、connection():全局 dag 客户端

函数签名

connection(fct: () => Promise<void>, cfg?: ConnectOpts): Promise<void>
  • fct() => Promise<void>,无参数回调。
  • cfg?ConnectOpts,默认值{}
  • 返回值:Promise<void>

参考文档对connection的定位是:connection executes the given function using the default global Dagger client.(使用默认的全局 Dagger 客户端执行给定函数)。这里的“全局客户端”即 SDK 代码生成文件中暴露的dag变量(见 api/client.gen.ts 中的export const dag)。

源码实现解读

export async function connection( fct: () => Promise<void>, cfg: ConnectOpts = {}, ) { try { telemetry.initialize() // Wrap connection into the opentelemetry context for propagation await opentelemetry.context.with(telemetry.getContext(), async () => { try { await withGQLClient(cfg, async (gqlClient) => { // Set the GQL client inside the global dagger client globalConnection.setGQLClient(gqlClient) await fct() }) } finally { globalConnection.resetClient() } }) } finally { await telemetry.close() } }

相比connect()connection()做了三件额外的事:

  1. 初始化并关闭 OpenTelemetry 遥测telemetry.initialize()在开头调用,telemetry.close()finally中兜底,确保任何路径下遥测资源都会被释放;同时整个回调被包进opentelemetry.context.with(...),用于跨异步边界的上下文传播(context propagation)。
  2. 注入全局 GQL 客户端globalConnection.setGQLClient(gqlClient)把当前会话的 GraphQL 客户端挂到全局Connection单例上,之后dag的所有操作都走这个客户端。
  3. 会话结束清理finallyglobalConnection.resetClient()把全局客户端置空,避免泄漏到下一个连接。

参考文档示例

参考文档为connection提供了可直接运行的示例——构建一个 Alpine 容器、安装 curl 并抓取 dagger.io 首页,全程无需手写Client

await connection( async () => { await dag .container() .from("alpine") .withExec(["apk", "add", "curl"]) .withExec(["curl", "https://dagger.io/"]) .sync() }, { LogOutput: process.stderr } )

该示例与源码注释中的@example完全一致,是connection()最典型的用法:回调体内直接使用全局dag变量,配置项只需按需传入。

六、底层连接机制:withGQLClient 与会话建立

无论是connect还是connection,最终都汇聚到 sdk/typescript/src/common/graphql/connect.ts 的withGQLClient。它的职责注释写得很清楚:Execute the callback with a GraphQL client connected to the Dagger engine. It automatically provisions the engine if needed.(用连接到 Dagger 引擎的 GraphQL 客户端执行回调;必要时自动拉起引擎)。

其决策逻辑分两条路径:

export async function withGQLClient<T>( connectOpts: ConnectOpts, cb: (gqlClient: GraphQLClient) => Promise<T>, ): Promise<T> { if (process.env["DAGGER_SESSION_PORT"]) { const port = process.env["DAGGER_SESSION_PORT"] if (!process.env["DAGGER_SESSION_TOKEN"]) { throw new Error( "DAGGER_SESSION_TOKEN must be set if DAGGER_SESSION_PORT is set", ) } const token = process.env["DAGGER_SESSION_TOKEN"] return await cb(createGQLClient(Number(port), token)) } try { const provisioning = await import("../../provisioning/index.js") return await provisioning.withEngineSession(connectOpts, cb) } catch (e) { throw new Error( `failed to execute function with automatic provisioning: ${e}`, { cause: e }, ) } }
  • 直连已有会话(Session 内运行):当环境变量DAGGER_SESSION_PORT存在时,SDK 认为当前进程运行在 Dagger 会话(例如模块运行时、dagger call内)中,此时必须同时提供DAGGER_SESSION_TOKEN,否则直接抛出DAGGER_SESSION_TOKEN must be set if DAGGER_SESSION_PORT is set。通过createGQLClient(port, token)建立 GraphQL 客户端,不再自行启动引擎。
  • 自动 provisioning:否则动态导入 sdk/typescript/src/provisioning/index.ts 中的withEngineSession,自动完成引擎二进制下载、引擎启动、会话协商等全套流程(对应ConnectOpts中的工作目录与日志配置也在此生效)。任何失败都会被包装为failed to execute function with automatic provisioning: ...并带上原始cause

而 sdk/typescript/src/common/graphql/connection.ts 中的Connection类则负责 GraphQL 客户端的生命周期管理:

export class Connection { constructor(private _gqlClient?: GraphQLClient) {} resetClient() { this._gqlClient = undefined } setGQLClient(gqlClient: GraphQLClient) { this._gqlClient = gqlClient } getGQLClient(): GraphQLClient { if (!this._gqlClient) { throw new Error("GraphQL client is not set") } return this._gqlClient } } export const globalConnection = new Connection()

globalConnection是包级单例:connection()用它挂载/重置全局客户端;Context求值时通过getGQLClient()惰性取用。若在未连接状态下调用会得到明确的GraphQL client is not set错误——这也解释了为什么所有流水线代码都必须包在connect/connection回调内部执行。

七、connect() 与 connection() 如何选择

维度connect(cb, config?)connection(fct, cfg?)
回调参数显式传入Client实例无参数,使用全局dag
适合场景普通脚本 / CLI 程序,显式拿到客户端模块代码或习惯用dag全局变量的场景
遥测不主动初始化/关闭自动初始化并关闭 OpenTelemetry 遥测
版本检查连接时调用client.version()并告警不显式检查(依赖全局客户端)
连接清理withGQLClient结束即释放额外resetClient()重置全局单例

实践中两者可互换的场景很多:把connection示例中的dag换成client就等价于connect的写法。但请注意保持统一——connection依赖全局客户端状态,若在同一个进程里先connectconnectionglobalConnection的状态可能互相干扰,因此官方建议按项目约定固定使用其一。

八、完整实战:一个可运行的 CI/CD 脚本

综合上文所有内容,下面是一个功能完整的示例:连接引擎、读取宿主工作目录、执行容器构建,并开启日志输出与版本检查告警。

import { connect } from "@dagger.io/dagger" async function main() { await connect( async (client) => { // 1. 查看宿主工作目录(受 ConnectOpts.Workdir 影响) const workdir = client.host().workdir() console.log("workdir entries:", await workdir.entries()) // 2. 构建并运行一个 Alpine 容器任务 const out = await client .container() .from("alpine:3.20") .withExec(["sh", "-c", "echo DAGGER_OK && uname -a"]) .stdout() console.log("container output:", out) }, { Workdir: process.cwd(), // 默认值,可显式覆盖 LogOutput: process.stderr, // 引擎日志输出到 stderr LoadWorkspaceModules: false, // 默认仅核心 API }, ) } main().catch((err) => { console.error(err) process.exit(1) })

配套的工程化准备(来自 TypeScript SDK 说明文档):

# 安装 SDK(建议作为开发依赖) npm install @dagger.io/dagger --save-dev # SDK 以 ESM 类型模块导出,项目需声明相同类型 npm pkg set type=module # tsconfig.json 需使用 NodeNext 模块解析 # "module": "NodeNext"

运行时若设置了DAGGER_SESSION_PORT(例如在 Dagger 模块会话中),SDK 会直连现有引擎而不重复启动;否则会自动 provisioning 一个引擎会话,因此这段代码既可以本地ts-node直接跑,也能放进dagger call的模块上下文中执行。

九、进一步探索

  • API 参考:完整的 TypeScript SDK 模块索引、Client 客户端类 以及dag全局变量说明。
  • 源码:连接核心 connect.ts 与 connectOpts.ts;会话建立 common/graphql/connect.ts 与 common/graphql/connection.ts;自动 provisioning 见 provisioning。
  • 测试:connect.spec.ts 提供了connect/connection的端到端用例,适合作为学习连接语义的补充材料。
  • 其他语言 SDK 的同类连接入口可在 sdk 目录下对照查看(Go、Python、Java、PHP、Rust 等)。

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

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

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

立即咨询