
Dagger 函数结果缓存策略解析TypeScript SDK 中 FunctionCachePolicy 枚举的三种取值与底层实现【免费下载链接】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 v0.20 系列 TypeScript API 参考文档中FunctionCachePolicy枚举的深度解读。该枚举用于配置 Dagger 模块中函数Function返回结果的缓存行为是模块作者控制函数调用结果是否被缓存、缓存多久的核心开关。读完本文你将掌握Default、Never、PerSession三种策略的语义差异、与withCachePolicy及 TTL 参数的配合方式以及它们在 Dagger 引擎缓存层面的实际作用原理。枚举概述什么是 FunctionCachePolicyFunctionCachePolicy定义于 TypeScript SDK 的自动生成客户端中描述的是函数结果缓存的配置行为The behavior configured for function result caching。它是 Dagger 模块 API 中Function_对象的一个配置维度由模块运行时在注册函数时写入并最终驱动引擎层决定调用结果的持久化方式。该枚举的官方 TS 定义为 sdk/typescript/src/api/client.gen.ts/** * The behavior configured for function result caching. */ export enum FunctionCachePolicy { Default Default, Never Never, PerSession PerSession, }它只包含三个枚举成员每个成员对应一个字符串值Default、Never、PerSession。在 GraphQL Schema 层面对应FunctionCachePolicy枚举类型其完整定义可见引擎基准 Schema core/schema/testdata/base_schema.graphqls 中Function.withCachePolicy字段的参数类型。枚举成员详解Default —— 默认缓存策略Default:Default这是默认值也是未显式设置缓存策略时函数所采用的策略。语义为函数结果按照 Dagger 的默认规则进行缓存与持久化。从源码看当函数元数据中的CachePolicy为空时会被统一归一到Default见 core/typedef.go 的derivedCachePolicyfunc (fn *Function) derivedCachePolicy(mod *Module) FunctionCachePolicy { cachePolicy : fn.CachePolicy if cachePolicy { cachePolicy FunctionCachePolicyDefault } if cachePolicy FunctionCachePolicyDefault mod.DisableDefaultFunctionCaching { // older modules that explicitly disable the new default function caching should // fallback to the old caching behavior (per-session) cachePolicy FunctionCachePolicyPerSession } return cachePolicy }值得注意的细节是Default策略下引擎为函数结果设置持久化属性IsPersistable true并写入 TTL——若函数显式指定了CacheTTLSeconds则使用该值否则使用上限MaxFunctionCacheTTLSeconds即 7 天见 core/modfunc.go 的常量定义作为非常原始的剪枝手段。对应代码在 core/typedef.gocachePolicy : fn.CachePolicy if cachePolicy { cachePolicy FunctionCachePolicyDefault } ... spec.IsPersistable true switch cachePolicy { case FunctionCachePolicyNever: spec.IsPersistable false case FunctionCachePolicyPerSession: spec.IsPersistable false case FunctionCachePolicyDefault: if fn.CacheTTLSeconds.Valid { spec.TTL fn.CacheTTLSeconds.Value.Int64() } else { // we still set a max TTL for now as a very primitive form of pruning spec.TTL MaxFunctionCacheTTLSeconds } }同时Default也是唯一允许搭配 TTLtimeToLive的缓存策略。Never —— 永不缓存Never:Never该策略表示函数结果不被持久化缓存。每次调用都会重新执行函数体适用于那些结果不应被复用例如含随机性、实时性要求高、或产生副作用的函数。引擎侧的行为同样可见于上面的switch分支FunctionCachePolicyNever使spec.IsPersistable false即该函数调用结果不会进入持久化缓存。在调用图层面core/modfunc.go 的cacheImplicitInputs会为Never策略附加一个dagql.PerCallInput隐式输入var implicitInputs []dagql.ImplicitInput cachePolicy : fn.metadata.derivedCachePolicy(fn.mod.Self()) switch cachePolicy { case FunctionCachePolicyNever: implicitInputs append(implicitInputs, dagql.PerCallInput) case FunctionCachePolicyPerSession: implicitInputs append(implicitInputs, dagql.PerSessionInput) }PerCallInput意味着每次调用都被视为独立、不可共享缓存结果的节点从而强制重算。PerSession —— 按会话缓存PerSession:PerSession该策略表示函数结果仅在当前 Dagger 会话Session内有效。同一会话中的后续调用可以命中缓存但会话结束、新会话启动后缓存即失效结果不会被跨会话持久化。这与Never的区别在于Never连同一次会话内的重复调用也不缓存而PerSession至少在会话生命周期内可以复用结果。在引擎侧PerSession同样使IsPersistable false不跨会话持久化但在cacheImplicitInputs中附加的是dagql.PerSessionInput即以会话为作用域进行缓存。另外PerSession也是 Dagger 旧版默认缓存行为。derivedCachePolicy中特意处理了旧模块显式禁用默认函数缓存的兼容场景当模块设置了DisableDefaultFunctionCaching时Default会回退为PerSession保持老模块原有的按会话缓存语义不变core/typedef.go。枚举的配套工具函数SDK 生成代码还提供了两个配套的转换工具函数用于在枚举值与字符串名之间互转供模块运行时在调用 GraphQL API 时使用见 sdk/typescript/src/api/client.gen.ts/** * Utility function to convert a FunctionCachePolicy value to its name so * it can be uses as argument to call a exposed function. */ export function FunctionCachePolicyValueToName( value: FunctionCachePolicy, ): string { switch (value) { case FunctionCachePolicy.Default: return Default case FunctionCachePolicy.Never: return Never case FunctionCachePolicy.PerSession: return PerSession default: return value } } /** * Utility function to convert a FunctionCachePolicy name to its value so * it can be properly used inside the module runtime. */ export function FunctionCachePolicyNameToValue( name: string, ): FunctionCachePolicy { switch (name) { case Default: return FunctionCachePolicy.Default case Never: return FunctionCachePolicy.Never case PerSession: return FunctionCachePolicy.PerSession default: return name as FunctionCachePolicy } }FunctionCachePolicyValueToName将枚举值转换为字符串名作为调用暴露函数exposed function时的参数FunctionCachePolicyNameToValue将字符串名解析回枚举值供模块运行时内部使用。这两者实际上支撑了 TypeScript SDK 在将缓存策略参数编码进 GraphQL 查询时所需的元数据标记。在withCachePolicy的实现中可以看到它如何被引用sdk/typescript/src/api/client.gen.ts/** * Returns the function updated to use the provided cache policy. * param policy The cache policy to use. * param opts.timeToLive The TTL for the cache policy, if applicable. Provided as a duration string, e.g. 5m, 1h30s. */ withCachePolicy ( policy: FunctionCachePolicy, opts?: FunctionWithCachePolicyOpts, ): Function_ { const metadata { policy: { is_enum: true, value_to_name: FunctionCachePolicyValueToName }, } const ctx this._ctx.select(withCachePolicy, { policy, ...opts, __metadata: metadata, }) return new Function_(ctx) }其中policy: { is_enum: true, value_to_name: FunctionCachePolicyValueToName }告知序列化层这是一个枚举参数需要经过value_to_name转换后再发送。使用方式withCachePolicy 与 TTL 参数枚举通过Function_.withCachePolicy(policy, opts?)方法应用到某个函数定义上。其 GraphQL 签名定义于 core/schema/testdata/base_schema.graphqlsReturns the function updated to use the provided cache policy. withCachePolicy( The cache policy to use. policy: FunctionCachePolicy! The TTL for the cache policy, if applicable. Provided as a duration string, e.g. 5m, 1h30s. timeToLive: String ): Function!参数说明参数类型必填说明policyFunctionCachePolicy是要采用的缓存策略取值为Default/Never/PerSessiontimeToLiveString时长字符串否缓存 TTL例如5m、1h30s仅适用于Default策略服务端解析逻辑位于 core/schema/module.go 的functionWithCachePolicyfunc (s *moduleSchema) functionWithCachePolicy( ctx context.Context, fn *core.Function, args struct { Policy core.FunctionCachePolicy TimeToLive dagql.Optional[dagql.String] }, ) (*core.Function, error) { fn fn.Clone() fn.CachePolicy args.Policy if args.TimeToLive.Valid { // For now, restrict TTLs to the default policy. We could support it // for PerSession in the future if desired. if fn.CachePolicy ! core.FunctionCachePolicyDefault { return nil, errors.New(time to live can only be set with default cache policy) } ttlDuration, err : time.ParseDuration(string(args.TimeToLive.Value)) if err ! nil { return nil, fmt.Errorf(failed to parse time to live duration %q: %w, args.TimeToLive.Value, err) } switch { case ttlDuration 0: // a TTL of 0 sounds an awful lot like never cache, so we treat it that way. fn.CachePolicy core.FunctionCachePolicyNever case ttlDuration core.MinFunctionCacheTTLSeconds*time.Second: return nil, fmt.Errorf(time to live duration must be at least %q, got %q, (core.MinFunctionCacheTTLSeconds * time.Second).String(), args.TimeToLive.Value, ) case ttlDuration core.MaxFunctionCacheTTLSeconds*time.Second: return nil, fmt.Errorf(time to live duration must be at most %q, got %q, (core.MaxFunctionCacheTTLSeconds * time.Second).String(), args.TimeToLive.Value, ) default: fn.CacheTTLSeconds dagql.NonNull(dagql.Int(int(ttlDuration.Seconds()))) } } return fn, nil }这里有几个关键的校验规则使用timeToLive时必须注意TTL 只能与Default策略搭配。对Never或PerSession传入 TTL 会直接报错time to live can only be set with default cache policyTTL 为 0 会被当作永不缓存引擎会将其转换为FunctionCachePolicyNever代码注释也承认TTL 为 0 听起来很像永不缓存TTL 有上下限下限为MinFunctionCacheTTLSeconds 1秒core/modfunc.go上限为MaxFunctionCacheTTLSeconds 7 * 24 * 60 * 60秒即1 周core/modfunc.go。超出范围会返回对应错误TTL 格式使用 Go 的time.ParseDuration语法如5m、1h30s、300s支持的单位包括ns、us/µs、ms、s、m、h。TTL 最终以秒为单位写入函数的CacheTTLSeconds元数据字段core/typedef.go 中Function结构体同时持有CachePolicy FunctionCachePolicy与CacheTTLSeconds dagql.Nullable[dagql.Int]并随模块定义序列化传递。模块运行时中的真实调用场景FunctionCachePolicy并非仅存在于类型定义层面它已被 TypeScript 模块运行时实际使用。在 sdk/typescript/src/module/entrypoint/register.ts 的addFunction中运行时根据函数声明里的cache配置自动映射到对应策略switch (fct.cache) { case never: { fnDef fnDef.withCachePolicy(FunctionCachePolicy.Never) break } case session: { fnDef fnDef.withCachePolicy(FunctionCachePolicy.PerSession) break } case : { break } default: { const opts: FunctionWithCachePolicyOpts { timeToLive: fct.cache } fnDef fnDef.withCachePolicy(FunctionCachePolicy.Default, opts) } }映射关系一目了然cache: never→FunctionCachePolicy.Never函数结果永不缓存cache: session→FunctionCachePolicy.PerSession结果仅在当前会话内缓存cache为空 → 不显式设置走Default默认行为cache为其他字符串如5m、1h→ 视为 TTL 时长字符串以DefaulttimeToLive调用。这印证了在 Dagger 模块源码中声明函数缓存行为时只需用cache装饰/注解例如 core/integration/testdata/modules/dang/test-directives/main.dang 中cache(policy: FunctionCachePolicy.Never)的用法运行时便会自动转换为上述withCachePolicy调用链。引擎侧的持久化语义综合前面的源码证据三种策略在引擎层面的核心区别可以归纳如下依据 core/typedef.go 与 core/modfunc.go策略结果持久化IsPersistable缓存作用域TTL 行为Default是true跨会话持久化显式 TTL未设置时使用上限 1 周Never否false无每次调用独立PerCallInput不可设置TTL 仅限 DefaultPerSession否false当前会话内PerSessionInput不可设置TTL 仅限 Default此外Default与PerSession之间还存在一条兼容性回退路径当模块显式设置DisableDefaultFunctionCaching旧模块为保持旧行为而禁用默认函数缓存时Default会被derivedCachePolicy改写为PerSessioncore/typedef.go从而延续旧版会话级缓存的语义。参考与延伸阅读枚举权威定义sdk/typescript/src/api/client.gen.tswithCachePolicy客户端实现sdk/typescript/src/api/client.gen.ts模块运行时策略映射sdk/typescript/src/module/entrypoint/register.tsGraphQL Schema 定义core/schema/testdata/base_schema.graphqls服务端解析与 TTL 校验core/schema/module.go缓存策略推导与持久化标记core/typedef.go隐式缓存输入与 TTL 常量core/modfunc.go、core/modfunc.go相关枚举参考TypeScript API 参考索引、模块概览【免费下载链接】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),仅供参考