news 2026/9/17 8:06:36

Dagger TypeScript SDK 错误体系解析:FunctionNotFound 错误类的定义、触发场景与降级机制

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Dagger TypeScript SDK 错误体系解析:FunctionNotFound 错误类的定义、触发场景与降级机制

Dagger TypeScript SDK 错误体系解析:FunctionNotFound 错误类的定义、触发场景与降级机制

【免费下载链接】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 中的FunctionNotFound错误类,结合官方 API 文档与 SDK 源码,系统讲解该错误的类定义、构造参数、属性与方法、底层实现,以及它在 Dagger 模块执行器与入口调用链中的真实触发场景和注册表降级机制。读完本文,你将掌握如何识别、捕获并程序化处理 Dagger 模块运行期的"函数/对象未找到"错误,并能理解整个 DaggerSDKError 错误码体系(D100~D110)的设计脉络。

一、文档定位:一个位于错误体系顶层的 API 引用页

在 Dagger 的版本化文档中,FunctionNotFound.md 是 TypeScript SDKcommon/errors模块的类参考页之一,它与DaggerSDKErrorExecErrorGraphQLRequestErrorUnknownDaggerError等十余个错误类共同构成了 SDK 的错误类型目录(完整清单见 common/errors 索引)。

该页面给出的核心 API 签名如下:

class FunctionNotFound extends DaggerSDKError { // 构造器 new FunctionNotFound(message: string, options?: DaggerSDKErrorOptions): FunctionNotFound // 属性 code: "D109" = ERROR_CODES.ExecError name: "ExecError" = ERROR_NAMES.ExecError message: string cause?: Error stack?: string // 方法 printStackTrace(): void }

从类名即可看出,FunctionNotFound表达的是"函数未找到"这一语义——当 Dagger 在解析或调用某个模块对象及其方法时无法找到对应实现,就会抛出该错误。下面逐项拆解这个类。

二、继承关系与构造器

FunctionNotFound直接继承自DaggerSDKError(详见 DaggerSDKError 类文档)。在 SDK 源码中,这层关系由 FunctionNotFound.ts 体现:

import { DaggerSDKError, DaggerSDKErrorOptions } from "./DaggerSDKError.js" import { ERROR_CODES, ERROR_NAMES } from "./errors-codes.js" export class FunctionNotFound extends DaggerSDKError { name = ERROR_NAMES.ExecError code = ERROR_CODES.ExecError constructor(message: string, options?: DaggerSDKErrorOptions) { super(message, options) } }

构造参数

参数类型必填说明
messagestring错误描述信息,由抛出方填充(例如Object foo not found
options?DaggerSDKErrorOptions可选配置,目前仅支持cause字段,用于携带导致本次错误的原始Error

DaggerSDKErrorOptions定义在 DaggerSDKError.ts:

export interface DaggerSDKErrorOptions { cause?: Error }

构造函数内部直接调用基类构造函数:super(message, options),基类会执行super(message)并读取options?.cause赋值给实例的cause属性。

关于文档首行描述的一个细节

该参考页首行写着 "The base error. Every other error inherits this error."(基类错误,其他错误均继承自它)。从源码结构看,这句话实际与 DaggerSDKError.ts 中基类的 JSDoc 注释完全一致,属于 TypeDoc 自动生成文档时沿用的基类描述。真实情况是:DaggerSDKError才是整个错误体系的基础类,FunctionNotFound只是它的一个具体子类。阅读文档时留意这一点,可以避免对继承层级产生误解。

三、属性详解

3.1 name 与 code:被复用的错误标识

这是FunctionNotFound最值得注意的实现细节:它的namecode并不是专属值,而是直接复用了ExecError的常量:

name = ERROR_NAMES.ExecError // 实际值 "ExecError" code = ERROR_CODES.ExecError // 实际值 "D109"

也就是说,从错误码角度,FunctionNotFoundExecError共享"D109"与名称"ExecError"。这一点在 errors-codes.ts 中可以确认:

export const ERROR_CODES = { GraphQLRequestError: "D100", UnknownDaggerError: "D101", TooManyNestedObjectsError: "D102", EngineSessionConnectParamsParseError: "D103", EngineSessionConnectionTimeoutError: "D104", EngineSessionError: "D105", InitEngineSessionBinaryError: "D106", DockerImageRefValidationError: "D107", NotAwaitedRequestError: "D108", ExecError: "D109", IntrospectionError: "D110", } as const

注意ERROR_CODES被声明为as const,因此每个值都是字面量类型;ERROR_NAMES则通过Object.keys(ERROR_CODES)反向生成,保证名称与码表一一对应。这意味着你在代码中看到error.code === "D109"时,它既可能来自ExecError,也可能来自FunctionNotFound——不要仅凭错误码区分这两类错误,建议配合instanceof判断具体类型

3.2 message 与 stack

  • message: string:继承自Error,保存构造时传入的错误描述。
  • stack?: string:标准 V8 堆栈信息,同样继承自基类。可选属性的语义与原生Error.stack一致,仅在 V8 生成堆栈后可用。

3.3 cause?: Error

causeDaggerSDKError体系引入的"原始错误"承载字段:

/** * The original error, which caused the DaggerSDKError. */ cause?: Error

它用于错误链(error chaining):当 SDK 在捕获到某个底层错误后需要包装为 Dagger 语义错误时,可将原始错误挂到cause上,方便调试时追溯根因。FunctionNotFound自身并未重写该字段,完全继承自基类,因此它是可选的(optional)。

四、方法:printStackTrace()

FunctionNotFound继承自基类的唯一公开方法printStackTrace(): void,用于"漂亮地打印"错误堆栈。其实现位于 DaggerSDKError.ts:

printStackTrace() { log(this.stack) }

它调用 SDK 内部的log工具函数输出this.stack。该方法的可见性为公开(TypeDoc 标记为@hiddenSymbol.toStringTaggetter 除外),便于在捕获错误后快速在控制台定位调用链。

五、触发场景:模块执行器中的三处抛错点

FunctionNotFound的实际抛出位置集中在 executor.ts,它承担着 Dagger TypeScript 模块运行期"按名解析对象与方法并执行"的核心职责:

抛错点方法消息模板触发条件
第一处getExportedObject`Object ${object} not found`在当前已加载的所有Module中找不到导出对象
第二处buildClass`Object ${object} not found in the module`在模块的 introspection 对象表中找不到该对象定义
第三处getResult`Method ${method} not found`对象存在,但实例上不存在要调用的方法

对应源码摘录:

// executor.ts - getExportedObject const module = this.modules.find((m) => m[key] !== undefined) if (!module) { throw new FunctionNotFound(`Object ${object} not found`) } // executor.ts - buildClass const daggerObject = this.daggerModule.objects[object] if (!daggerObject) { throw new FunctionNotFound(`Object ${object} not found in the module`) } // executor.ts - getResult const builtObj = this.buildClass(object, state) if (!builtObj[method]) { throw new FunctionNotFound(`Method ${method} not found`) }

从源码结构可以推断出典型触发场景:当外部调用方通过 GraphQL 请求一个不存在的 Dagger 对象(例如dag.getFoo()),或请求对象上并不存在的方法(例如对某个@object()装饰的类调用未用@func()暴露的方法)时,执行器就会以FunctionNotFound中断调用。这是模块 API 与实现不匹配时的第一道防线。

六、关键机制:invoke 入口的注册表降级

FunctionNotFound并非只用于"直接失败",它还在 invoke.ts 中扮演了降级切换的触发信号角色。入口函数invoke在调用executor.getResult时包裹了 try/catch:

try { result = await executor.getResult(object.name, method.name, parentState, args) } catch (e) { // If the function isn't found because it's // not exported, we try to get the result from the registry. if (e instanceof FunctionNotFound) { result = await registry.getResult(object.name, method.name, parentState, args) } else { throw e } }

其逻辑可归纳为:

  1. 优先尝试从模块的导出对象executor持有的Module[])中解析并调用函数;
  2. 若抛出FunctionNotFound,说明该函数未通过模块导出,则转而查询registry(registry.ts);
  3. registry是由@object()装饰器注册的类与方法的仓储结构,内部以 map 作为数据结构以优化查找性能(见 registry.ts 中的RegistryClass定义);
  4. 只有instanceof FunctionNotFound才会触发降级,其他错误一律原样上抛——这保证了降级路径的精确性。

换句话说,FunctionNotFound在 Dagger 模块运行模型中承担"双轨解析"的哨兵职责:导出解析失败时,它作为可预期信号驱动注册表回退,避免模块中大量通过装饰器注册但未显式导出的函数无法被调用。这也是该错误类与ExecError共享错误码却仍有独立类名的现实意义——运行时依赖instanceof而非code做分支判断。

七、实战:如何识别与处理 FunctionNotFound

7.1 程序化识别

文档明确说明code的用途是 "Use this to identify dagger errors programmatically"(用错误码在程序中识别 Dagger 错误)。结合上文,推荐的识别姿势是instanceof优先:

import { FunctionNotFound, ExecError } from "@dagger.io/dagger/common/errors" try { const result = await someModuleFunction() } catch (e) { if (e instanceof FunctionNotFound) { // 对象或方法未找到,可提示调用方检查 API 名称 console.error(`module resolution failed: ${e.message}`) e.printStackTrace() } else if (e instanceof ExecError) { // 真正的执行期错误(注意两者 code 均为 "D109") console.error(`exec error: ${e.message}`, { cause: e.cause }) } else { throw e } }

如果需要跨版本兼容或无法直接import具体类,可退而使用错误码:if ((e as DaggerSDKError).code === "D109")。但要牢记 §3.1 的结论——"D109"同时属于ExecErrorFunctionNotFound,仅凭码无法区分两者。

7.2 调试建议

  • 查看message:三种模板(Object xxx not foundObject xxx not found in the moduleMethod xxx not found)直接指示是对象级还是方法级解析失败;
  • 调用printStackTrace()输出完整调用链;
  • 检查cause:若错误由其他底层异常包装而来,cause中保存原始Error
  • 若出现"导出解析失败但注册表降级也未命中"的情况,请核对模块是否用@object()/@func()正确装饰类与方法(相关装饰器语义见 registry.ts 中的FunctionOptions,其中alias可用于为函数设置对外暴露的别名,cache可控制函数的缓存策略)。

八、在错误体系中的位置

FunctionNotFound属于 common/errors 目录 下 12 个错误类之一,整个体系的骨架是:

Error └─ DaggerSDKError (抽象基类,含 name / code / cause / printStackTrace) ├─ FunctionNotFound (code D109,与 ExecError 共用) ├─ ExecError (code D109) ├─ GraphQLRequestError (code D100) ├─ UnknownDaggerError (code D101) ├─ TooManyNestedObjectsError (code D102) ├─ EngineSessionConnectParamsParseError (code D103) ├─ EngineSessionConnectionTimeoutError (code D104) ├─ EngineSessionError (code D105) ├─ InitEngineSessionBinaryError (code D106) ├─ DockerImageRefValidationError (code D107) ├─ NotAwaitedRequestError (code D108) └─ IntrospectionError (code D110)

所有错误类的名称与错误码统一定义在 errors-codes.ts,由as const保证类型安全,ERROR_NAMES由码表键名自动推导。理解这张表,你就掌握了整个 Dagger TypeScript SDK 错误信号的"字母表"——D100D110覆盖了从 GraphQL 请求、引擎会话建立、镜像引用校验、执行错误到模块内省失败的各类故障域,而FunctionNotFound正是其中负责"模块函数解析"一环的关键成员。

参考文件索引

  • 类 API 文档:FunctionNotFound.md
  • 错误模块索引:common/errors/README.md
  • 类实现:FunctionNotFound.ts
  • 基类实现:DaggerSDKError.ts
  • 错误码表:errors-codes.ts
  • 抛错点:executor.ts
  • 注册表降级:invoke.ts
  • 注册表实现:registry.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),仅供参考

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

门诊系统数据库设计实战:从E-R图到MySQL实现

简介:面向高校软件工程、数据库应用系统等课程的学生,这份医院门诊管理系统数据库设计课程设计文档,完整展示了一个小型医院门诊系统的数据库分析与设计全过程。内容从需求分析切入,先借助数据流程图梳理病人挂号、诊断治疗、收费…

作者头像 李华