跳到主要内容

领域模型:Flow / Task / Execution / State

30 秒导读: Kestra 是一个"写 YAML 就能编排任务"的工作流引擎。这一章只讲名词和数据模型——一份 YAML 怎么变成内存里的对象(Flow),运行时又怎么被表示(Execution / TaskRun),以及所有运转状态都压进哪一台状态机枚举(State.Type)。只讲"东西是什么、状态有哪些",不讲"状态怎么推进"——那是第 2 章 执行引擎的活。


1. 这是什么(零基础也能懂)

一句话定义: Kestra 的领域模型,就是"一份工作流 YAML"在代码里对应的那几个 Java 类。

先建立最重要的一个直觉——蓝图 vs 实例:

你写的代码里的类类比
一份 flow YAML(定义)Flow菜谱 / 类(class)
点一次"运行"产生的一次运行Execution按菜谱做的这一顿饭 / 对象(instance)
flow 里的一个 task 定义Task(子类)菜谱里的一个步骤
那个 task 这次实际跑出来的记录TaskRun这顿饭里"切菜"这一步的实况
任何东西此刻处于什么阶段State步骤旁边贴的"进行中/已完成"便签

一句话记牢:Flow / Task 是定义(写死在 YAML 里,不动);Execution / TaskRun 是运行时(每跑一次新生一批);State 贴在后两者身上记录它们走到哪一步了。

用起来什么样。 一份最小的 flow YAML 长这样:

id: hello
namespace: company.team
inputs:
- id: name
type: STRING
defaults: World
tasks:
- id: greet
type: io.kestra.plugin.core.log.Log
message: "Hello {{ inputs.name }}"

这份文本被解析后,id/namespace/inputs/tasks 分别落到 Flow 对象的对应字段上。点一次运行,引擎就为它造一个 Execution,并为 greet 这个 task 造一个 TaskRun,两者的 StateCREATED 开始往前走。


2. 顶层全景(这几个对象怎么串起来)

怎么读这张图: 左边是"定义层"(YAML 解析出来的,只读蓝图),右边是"运行时层"(每次运行新造的实例)。中间那道竖线就是"从蓝图实例化"这一步。

定义层 (蓝图, 来自 YAML) 运行时层 (每次运行新建)
┌──────────────────────────┐ ┌──────────────────────────┐
│ Flow │ │ Execution │
│ ├─ id / namespace │ 实例化 │ ├─ id / flowId │
│ ├─ inputs: List<Input> │ ──────▶│ ├─ state: State │
│ ├─ outputs: List<Output>│ │ └─ taskRunList ┐ │
│ └─ tasks: List<Task> ┐ │ └──────────────────┼───────┘
└────────────────────────┼──┘ │
│ ▼
每个 Task ┌──────────────────────────┐
┌──────────┴─────────┐ │ TaskRun │
│ RunnableTask (跑) │ ─────▶│ ├─ taskId (指回定义) │
│ FlowableTask (控) │ │ ├─ state: State │
│ ExecutableTask(派) │ │ └─ attempts: │
└────────────────────┘ │ List<TaskRunAttempt>│
└──────────────────────────┘
State (枚举状态机, 贴在 Execution / TaskRun / Attempt 上)
CREATED → RUNNING → SUCCESS / FAILED / KILLED / ...

各部件一句话职责:

部件干什么在哪个文件
Flow一份 flow 的完整定义:任务列表、输入、输出、触发器core/models/flows/Flow.java
AbstractFlowFlow 的公共骨架:id、namespace、revision、inputscore/models/flows/AbstractFlow.java
Task单个任务定义的抽象基类;所有插件任务都继承它core/models/tasks/Task.java
Execution一次运行的完整快照:所有 TaskRun + 整体 statecore/models/executions/Execution.java
TaskRun一个 task 在这次运行里的实例 + 状态 + 尝试记录core/models/executions/TaskRun.java
State状态机:当前状态 + 历史,判定"跑完没/跑着没"core/models/flows/State.java
YamlParserYAML 文本 → 对象的入口core/serializers/YamlParser.java

主线走一遍(高层): YAML 文本 → YamlParser.parse 反序列化成 Flow → 触发运行时 Execution.newExecution(flow, ...) 造出 Execution → 引擎为每个待跑 task 造 TaskRun → 每个对象身上的 StateCREATED 逐步推进到终态。


3. 定义层:声明式 Flow

3.1 Flow 与它的继承链

一份 flow 的字段被拆到两层类里,靠 Lombok 的 @SuperBuilder 拼起来:

FlowInterface (契约)

AbstractFlow ← 公共身份字段: id / namespace / revision / inputs / outputs / labels

Flow ← 编排内容: tasks / errors / finally / triggers / outputs / concurrency

FlowWithSource ← 多带一个字段: source (原始 YAML 文本)

AbstractFlow 放"身份"字段。 id、namespace、revision、inputs、outputs、disabled 都在这里(core/models/flows/AbstractFlow.java:33-56,AbstractFlow)。注意几个校验约束是写死在注解上的:

  • id 必须匹配 ^[a-zA-Z0-9][a-zA-Z0-9._-]*,长度 1–100(AbstractFlow.java:31-33)。
  • namespace 只能小写,长度 1–150(AbstractFlow.java:36-38)。
  • revision(修订号)@Min(1),同一个 flow 每次改动 +1(AbstractFlow.java:40-41)。

Flow 放"编排内容"字段。 真正描述"跑什么、怎么跑"的都在这层(core/models/flows/Flow.java:48,Flow extends AbstractFlow):

字段类型含义行号
tasksList<Task>主任务列表,@NotEmptyFlow.java:72
errorsList<Task>出错时跑的任务Flow.java:75
_finallyList<Task>无论成败都跑(YAML 里叫 finally)Flow.java:80
afterExecutionList<Task>执行结束后的钩子任务Flow.java:87
triggersList<AbstractTrigger>触发器(定时/事件)Flow.java:90
outputsList<Output>暴露给其它 flow 的输出值Flow.java:104
concurrencyConcurrency并发上限策略Flow.java:96

finally 是 Java 关键字,不能当字段名,所以内部字段叫 _finally,再手写一个 getFinally() 把它以正常名字暴露出去(Flow.java:78-84)。这是个纯粹为绕开语言关键字的小技巧。

Flow 还提供一批"遍历任务树"的工具方法,后面章节会反复用到:

  • allTasks():把 tasks + errors + finally + afterExecution 平铺成一条流(Flow.java:138)。
  • allTasksWithChilds():递归展开——遇到 flowable 任务(见 §4)就下钻它的子任务(Flow.java:148-169)。
  • findTaskByTaskId(id):按 id 找定义,找不到抛 InternalException(Flow.java:222)。

3.2 FlowWithSource:为什么要多一个"带源码"的版本

Flow 刻意不保留原始 YAML 文本——它的 getSource() 直接返回 null,注释说得很直白:"保守起见,flow 绝不返回任何 source"(Flow.java:300-304)。

真正要展示/存原文时用子类 FlowWithSource,它就多一个 source 字段并 override getSource() 把文本吐出来(core/models/flows/FlowWithSource.java:15:45)。两个方向的转换都手写了字段拷贝:toFlow() 剥掉 source 降级成 Flow(FlowWithSource.java:17),静态 of(flow, source) 反过来包上 source(FlowWithSource.java:57)。

类头注释说 Flow 计划被废弃、推荐用 FlowWithSource(Flow.java:37-41)。当前代码里两者仍并存。

3.3 Input:一个 type 字段分出 18 种子类

Input<T> 是抽象类,靠 Jackson 的 @JsonTypeInfo + @JsonSubTypes,用 YAML 里的 type: 字段决定反序列化成哪个具体子类(core/models/flows/Input.java:29-51)。共 18 种,例如:

type: STRING → StringInput
type: INT → IntInput
type: FILE → FileInput
type: SELECT → SelectInput
type: SECRET → SecretInput
type: FORM → FormInput (可嵌子输入)
...共 18 种,见 Input.java:32-49

每个 Inputid / type / required(默认 true)/ defaults / prefill 等字段(Input.java:60-91),并要求子类实现 validate(T input)(Input.java:98)。

一个不显然的精华:FORM 类型可以包一层子输入,解析后要"拍平"。expandToLeaves() 把每个 FormInput 的孩子复制成一份 id 被改写成点号路径(environment + . + regionenvironment.region)的叶子输入(Input.java:112-130)。复制手段也很特别——走一次 Jackson round-trip(toMaptoMap 回来),因为这个抽象类没有 toBuilder(),而 round-trip 能顺带把子类类型重新解析回来(Input.java:140-144,copyWithId)。

3.4 Output:flow 对外暴露的返回值

Output 比 Input 简单得多:id / description / value(可为动态表达式)/ type / required(core/models/flows/Output.java:18)。它是 flow 级别的"返回值",给别的 flow 引用用(Flow.java:98-104 的字段说明)。

注意 outputs 字段在 AbstractFlow(:52)和 Flow(:104)里都声明了——Flow 这个覆盖版带了 @PluginProperty(dynamic = true),支持动态表达式。


4. 任务体系:三大接口分野

这是整个领域模型里最需要讲清楚的一处。所有 task 的定义都继承抽象类 Task(core/models/tasks/Task.java:39,Task implements TaskInterface),它只提供公共字段(id、type、retry、timeout、disabled、runIf 等,Task.java:41-92)。

但一个 task "属于哪一类",不看它继承谁,而看它实现了下面哪个接口。 三个接口互斥地回答"这个任务由谁来跑、跑出来是什么":

接口一句话由谁执行关键方法文件
RunnableTask<T>真正干活的叶子任务Workerrun(RunContext)RunnableTask.java:10
FlowableTask<T>控制流程,不干活ExecutorchildTasks / resolveNextsFlowableTask.java:21
ExecutableTask<T>派生出子流程执行ExecutorcreateSubflowExecutionsExecutableTask.java:20

Task 用一个 isFlowable() 一票判定归属:return this instanceof FlowableTask(Task.java:154-157)。

4.1 RunnableTask —— 在 Worker 里跑

最简单。整个接口就一个方法:

// RunnableTask.java:10
public interface RunnableTask<T extends Output> extends Plugin, WorkerJobLifecycle {
// 在 Worker 里被调用来真正执行任务
T run(RunContext runContext) throws Exception;
}

一句话:凡是"下载文件、发 HTTP 请求、跑一段脚本、写日志"这种真正产生副作用的任务,都是 RunnableTask,由 Worker 进程调 run() 执行(详见第 3 章 Worker 与 RunContext)。返回值 T extends Output 是这次运行产出的结构化输出。

4.2 FlowableTask —— 控制流程,自己不干活

ParallelSwitchEachSequentialSequential 这些"控制流"任务实现的是 FlowableTask。它们自己不产生副作用,只决定"接下来跑哪些子任务"。所以它们由 Executor 在编排循环里处理,而不是发给 Worker。

三个承重方法:

  • allChildTasks() —— 返回全部子任务(含 errors)(FlowableTask.java:45)。
  • childTasks(runContext, parentTaskRun) —— 解析出这一层要跑的子任务;对迭代型(如 EachSequential)会把所有迭代都展开(FlowableTask.java:53)。
  • resolveNexts(runContext, execution, parentTaskRun) —— 决定"下一步跑哪些",返回 List<NextTaskRun>;串行的返回一个,并行的返回"并发数"那么多个(FlowableTask.java:61)。

它还提供一个默认的 resolveState(...),把子任务们的状态汇总成父任务的状态(FlowableTask.java:76-87)——但具体怎么汇总、怎么推进是第 2 章的事,这里只需知道"父 flowable 的状态是子任务状态的函数"。

4.3 ExecutableTask —— 派生子流

ExecutableTask 专门给"我要跑另一个 flow"的任务用(典型是 Subflow / ForEachItem)。它由 Executor 处理,负责把"父任务"翻译成"一个或多个子 flow 的 Execution"。

关键方法:

  • createSubflowExecutions(...) —— 造出若干 SubflowExecution,每个将生成一次子 flow 运行(ExecutableTask.java:25)。
  • waitForExecution() —— 父任务要不要等子流跑完才算结束(ExecutableTask.java:42)。
  • subflowId() —— 返回子流标识 SubflowId(namespace, flowId, revision?)(ExecutableTask.java:47:54)。

RestartBehavior 枚举(NEW_EXECUTION / RETRY_FAILED)描述子流重启时的行为(ExecutableTask.java:66-69)。

一个 task 可以同时是 FlowableExecutable(比如需要遍历 + 派生子流的任务),接口互斥的只是"跑法"层面的语义,不是硬性的 Java 单继承限制。判定 Worker/Executor 归属靠的是 isFlowable()isSendToWorkerTask()(Task.java:154-162)。


5. 运行时层:Execution / TaskRun / Attempt

定义层是死的蓝图。点一次运行,引擎按蓝图新造一批运行时对象。

5.1 Execution:一次运行的完整快照

Execution 是一次运行的顶层容器(core/models/executions/Execution.java:56)。核心字段:

字段含义行号
id这次运行的唯一 idExecution.java:71
flowId / namespace / flowRevision指回它跑的是哪个 flow 的哪个修订Execution.java:74-81
taskRunList这次运行里所有 TaskRunExecution.java:84
inputs / outputs实际输入值 / 产出值Execution.java:89:94
state整个 execution 的状态Execution.java:105
metadata尝试次数、原始创建时间等Execution.java:121

怎么诞生的: 静态工厂 newExecution(flow, inputs, labels, scheduleDate, kind)——用 IdUtils.create() 生成新 id,state 初始化为 new State()(即 CREATED),从 flow 拷 namespace/flowId/revision/variables,并保证挂上一个 correlation id 标签(Execution.java:192-224)。

导航方法(第 2 章会频繁调用):

  • findTaskRunsByTaskId(id) —— 按 task 定义 id 找出所有对应 TaskRun(Execution.java:482)。
  • findTaskRunByTaskRunId(id) —— 按 TaskRun 自己的 id 精确找,找不到抛 InternalException(Execution.java:493)。
  • findFirstByState(state) —— 找第一个处于某状态的 TaskRun(Execution.java:657)。

Execution 大量方法返回新对象而非原地改(如 withStatewithTaskRun,Execution.java:268:322)。它整体走不可变风格,状态推进 = 造一个字段替换过的副本。这一点是第 2 章状态机推进的地基。

5.2 TaskRun:一个 task 这次跑出来的实例

TaskRun 是"某个 Task 定义,在某次 Execution 里的一次实例"(core/models/executions/TaskRun.java:29)。核心字段:

字段含义行号
id这个 TaskRun 的唯一 idTaskRun.java:36
executionId属于哪次运行TaskRun.java:39
taskId指回哪个 task 定义TaskRun.java:48
parentTaskRunId父 TaskRun(嵌套/迭代时)TaskRun.java:50
value迭代场景下这次迭代的取值TaskRun.java:53
attempts尝试记录列表(重试会追加)TaskRun.java:56
state这个 TaskRun 的状态TaskRun.java:63
iteration第几次迭代(EachSequential 等)TaskRun.java:66

怎么诞生的: 静态工厂 TaskRun.of(execution, resolvedTask)——新建 id,从 execution 拷 tenant/namespace/flowId,从 resolvedTask 取 taskId/value,state 初始化为 new State()(TaskRun.java:189-202)。

Execution 一样,TaskRun 也是不可变风格:withState(type) 造一个换了 state 的副本(TaskRun.java:94),withStateAndAttempt(type) 顺带更新最后一次尝试(TaskRun.java:114),fail() 追加一次 FAILED 尝试(TaskRun.java:143)。

5.3 TaskRunAttempt:一次尝试

一个 TaskRun 可能被重试多次,每次是一个 TaskRunAttempt(core/models/executions/TaskRunAttempt.java:15)。字段极简:state(这次尝试的状态)、workerId(哪个 worker 跑的)、logFile(日志文件 URI)。它也是不可变的:withState 返回新副本(TaskRunAttempt.java:26)。

一句话理解层级:Execution(整次运行) ⊃ TaskRun(每个任务实例) ⊃ TaskRunAttempt(每次重试尝试),而这三层身上各贴一个 State

5.4 NextTaskRun:一个"待跑"的配对

NextTaskRun 是个极薄的配对结构,把"下一步要跑的 TaskRun"和"它对应的 Task 定义"绑在一起(core/models/executions/NextTaskRun.java:11):

// NextTaskRun.java:11
public class NextTaskRun {
TaskRun taskRun; // 运行时实例(还没跑)
Task task; // 它对应的定义
}

FlowableTask.resolveNexts(...) 返回的就是 List<NextTaskRun>(见 §4.2)——把"蓝图 + 待造实例"一起递给引擎。它是定义层和运行时层之间的一枚"接头"。


6. 状态机枚举:一台状态,处处复用

关键设计: Execution、TaskRun、TaskRunAttempt 三者用的是同一个 State 类(core/models/flows/State.java:26)。也就是说"运行状态"这个概念在整个系统里只有一套词汇表。

6.1 State 的结构

State 是不可变值对象(@Value),两个字段:

  • current —— 当前状态(State.Type 枚举)(State.java:29)。
  • histories —— 一串 History(state, date),记录状态变迁的时间线(State.java:33:329)。

推进状态靠 withState(type):造一个新 State,把新状态追加进 histories;如果要改成的状态和当前一样,它拒绝并 warn(State.java:73-80)。注意:这只是"记一笔",真正"该不该推进、推进到哪"是第 2 章 Executor 的决策——State 本身只负责记录和判定。

6.2 Type 枚举:17 个状态

State.Type 一共 17 个值(State.java:239-256):

CREATED SUBMITTED RUNNING PAUSED RESTARTED KILLING
SUCCESS WARNING FAILED KILLED CANCELLED QUEUED
RETRYING RETRIED SKIPPED BREAKPOINT RESUBMITTED

按"生命周期阶段"分组理解:

分组状态含义
起点CREATED / RESTARTED刚造出来 / 重启后待跑(isCreated(), State.java:271)
进行中RUNNING / KILLING跑着 / 正在被杀(isRunning(), State.java:275)
暂停PAUSED / BREAKPOINT手动暂停 / 断点停住
排队QUEUED / SUBMITTED / RESUBMITTED等资源 / 已提交
重试RETRYING / RETRIED正在重试 / 已重试
终态-成功SUCCESS / WARNING / SKIPPED成功 / 有告警 / 跳过
终态-失败FAILED / KILLED / CANCELLED失败 / 被杀 / 取消

6.3 判定方法:别硬比枚举,用语义函数

代码里几乎从不直接写 state == FAILED,而是调语义判定方法。这些方法是理解引擎逻辑的钥匙:

方法判什么定义
isTerminated()跑完了吗(任何终态)State.Type.isTerminated,State.java:258
isTerminatedNoFail()跑完且没失败(SUCCESS/WARNING/…)State.java:263
isTerminatedInError()跑完且是错(FAILED/KILLED/CANCELLED)State.java:267
isRunning()跑着吗(RUNNING/KILLING)State.java:275
isCreated()待跑吗(CREATED/RESTARTED)State.java:271

注意 isTerminated()FAILEDKILLEDCANCELLED 都算"终止",但 WARNINGSUCCESSSKIPPED 才算"无失败终止"(State.java:258-265)——这个区分是后面"整体成败判定"的基础。

一个精华判定:Type.fail(task) 一个任务失败时最终落成什么状态,取决于它的 allowFailure / allowWarning 配置(State.java:324-326):

// State.java:324 —— 失败降级三档
// 两个都 true → SUCCESS(当没事)
// 只 allowFailure → WARNING(记个告警)
// 都没有 → FAILED(真失败)
public static State.Type fail(Task task) {
return task.isAllowFailure() ? (task.isAllowWarning() ? SUCCESS : WARNING) : FAILED;
}

State 层面还带了一批"能不能"判定,供上层决策:canBeRestarted()(失败或暂停才可重启,State.java:155)、canChangeStatus()(已终止且非 KILLED,State.java:160)。这些是"判定"不是"推进"——谁在什么时机调它们,第 2 章讲。


7. YAML → 对象:解析入口

前面所有对象怎么从一份 YAML 文本变出来?入口是 YamlParser(core/serializers/YamlParser.java:25)。

核心方法 parse(input, cls) 反序列化文本成目标类(YamlParser.java:37)。它内部用两台 ObjectMapper:

  • STRICT_MAPPER —— 开了 FAIL_ON_UNKNOWN_PROPERTIES,YAML 里有多余字段直接报错(YamlParser.java:30-31)。
  • NON_STRICT_MAPPER —— 宽松版,遇未知字段忽略(YamlParser.java:26)。

两者都开了 STRICT_DUPLICATE_DETECTION——YAML 里同一个 key 写两遍会被抓出来(YamlParser.java:27)。

报错要人话。 解析失败不是甩 Jackson 的原始堆栈,而是翻译成友好信息:未知类型(用了不存在的 task type)→ Invalid type: xxx(YamlParser.java:123-143);缩进错乱 → "Check indentation…"(YamlParser.java:100-117)。全部包成 ConstraintViolationException 抛出。

底层的 mapper 从哪来。 YamlParser 用的 mapper 都源自 JacksonMapper.ofYaml()(core/serializers/JacksonMapper.java:89)。这台 YAML mapper 做了几处 flow YAML 友好的配置(JacksonMapper.java:76-87):MINIMIZE_QUOTES(少加引号)、不写文档起始 ---SPLIT_LINES 关掉(长行不折)。JacksonMapper 是全项目序列化的中枢,还提供 JSON、Ion 等多种 mapper(JacksonMapper.java:43)。

多态解析的魔法在字段上。 §3.3 说的 type: 决定子类,靠的就是 Jackson 的 @JsonTypeInfo(use = NAME, property = "type")(Input.java:29)。同理,Task 的具体插件类型也是 Jackson 按 type 字符串找到对应插件类反序列化的——这把"18 种输入 / 上千种插件任务"的分发,全交给了序列化框架,不需要手写 switch。


8. 巧妙之处(可带走的精华)

  1. 同一台 State 状态机复用三层。 Execution / TaskRun / Attempt 共用 State,状态词汇表全局唯一,判定逻辑(isTerminated 等)写一次处处可用(State.java:26)。

  2. 运行时对象全不可变。 withState / withTaskRun / fail 一律返回新副本(Execution.java:268TaskRun.java:94TaskRunAttempt.java:26)。状态推进变成"造替身",天然线程安全、易做事件溯源。

  3. 接口即角色,而非继承即角色。 一个 task 归 Worker 还是 Executor,不看它继承树,只看它实现 RunnableTask 还是 FlowableTask(Task.isFlowable,Task.java:154)。归属判定和字段定义彻底解耦。

  4. 失败降级三档表达力强。 allowFailure × allowWarning 两个布尔,压出 SUCCESS/WARNING/FAILED 三种落点(State.Type.fail,State.java:324),让"这个任务失败了但我不在乎"能精确表达。

  5. 多态解析外包给 Jackson。 type: 字段 + @JsonSubTypes 让新增输入类型/插件不用改解析器(Input.java:29-51)。


9. 边界与局限(诚实)

  • Flow 不存原文。 想要原始 YAML 必须用 FlowWithSource;Flow.getSource() 永远返回 null(Flow.java:300-304)。
  • Flow 计划废弃。 类注释推荐用 FlowWithSource(Flow.java:37-41),但迁移未完成,两者并存。
  • Input 抽象类没有 toBuilder() 想复制改字段只能走 Jackson round-trip(Input.java:140-144),这是 @SuperBuilder 未在抽象类生成 toBuilder() 的妥协。
  • 本章不含状态推进逻辑。 谁在什么时机把 CREATED 推成 RUNNING、flowable 的子状态如何汇总成父状态——全在第 2 章 Executor 状态机。这里的 State 只提供"记录 + 判定"两种能力。

10. 横向对比(同组其它章)

想知道去哪章
状态怎么被推进、Executor 怎么决策02-executor-state-machine.md
RunnableTask.run() 在哪跑、RunContext 是什么03-worker-and-runcontext.md
触发器(triggers 字段)怎么触发运行04-scheduler-and-triggers.md
Execution/TaskRun 怎么在组件间传递、怎么落库05-queue-and-persistence.md
插件任务怎么被发现、Web 层怎么接入06-plugins-and-webserver.md

11. 代码地图(导航索引)

主题文件路径关键符号
Flow 定义core/src/main/java/io/kestra/core/models/flows/Flow.javaFlow, allTasks, allTasksWithChilds, findTaskByTaskId
Flow 公共骨架core/src/main/java/io/kestra/core/models/flows/AbstractFlow.javaAbstractFlow, id, namespace, revision, inputs
带源码 Flowcore/src/main/java/io/kestra/core/models/flows/FlowWithSource.javaFlowWithSource, source, toFlow, of
输入类型core/src/main/java/io/kestra/core/models/flows/Input.javaInput, @JsonSubTypes, expandToLeaves, copyWithId
输出定义core/src/main/java/io/kestra/core/models/flows/Output.javaOutput, value, type
任务基类core/src/main/java/io/kestra/core/models/tasks/Task.javaTask, isFlowable, isSendToWorkerTask, findById
可运行任务core/src/main/java/io/kestra/core/models/tasks/RunnableTask.javaRunnableTask, run
可编排任务core/src/main/java/io/kestra/core/models/tasks/FlowableTask.javaFlowableTask, childTasks, resolveNexts, allChildTasks, resolveState
可派生子流任务core/src/main/java/io/kestra/core/models/tasks/ExecutableTask.javaExecutableTask, createSubflowExecutions, waitForExecution, SubflowId
运行时执行core/src/main/java/io/kestra/core/models/executions/Execution.javaExecution, newExecution, withState, findTaskRunByTaskRunId
任务运行实例core/src/main/java/io/kestra/core/models/executions/TaskRun.javaTaskRun, of, withState, withStateAndAttempt, fail
尝试记录core/src/main/java/io/kestra/core/models/executions/TaskRunAttempt.javaTaskRunAttempt, withState
待跑配对core/src/main/java/io/kestra/core/models/executions/NextTaskRun.javaNextTaskRun, taskRun, task
状态机core/src/main/java/io/kestra/core/models/flows/State.javaState, Type, withState, isTerminated, isRunning, fail
YAML 解析入口core/src/main/java/io/kestra/core/serializers/YamlParser.javaYamlParser, parse, STRICT_MAPPER, toConstraintViolationException
序列化中枢core/src/main/java/io/kestra/core/serializers/JacksonMapper.javaJacksonMapper, ofYaml, ofJson, toMap