跳到正文

运行如何流动 ​

一次运行从 开始 开始,沿接线从一个节点到下一个节点,当每个分支都完成且到达 结束 时结束。本页说明它遵循的规则;每个节点做什么见节点参考,随它流动的值见数据。

开始与结束 ​

一个实验恰好有一个 开始 和一个 结束。

  • 开始 没有输入。它立即通过,其时间线中的 行给出本次运行的种子。它的输出可以有多条接线:实验于是 以并行分支开始。
  • 到达 结束 的每个分支都在那里停止。End 从第一次 到达起就显示为运行中,并在最后一个分支完成后通过一次——如果有任何步骤失败则 完全不通过。正是这次通过使运行 通过。
  • 每个分支都无错误完成、但没有一个到达 End 的运行 会以 run.no_end 失败。

输出与接线 ​

节点的步骤以选择一个输出结束,运行会沿该输出的每一条接线继续。大多数节点有一个输出,输出;有些在多个之间选择:

节点必须接线的输出可以接线的输出
结束——
并行分支分支 1、分支 2—
按状态分支、按值分支是、否—
所有等待节点(等待 OSC、等待 UDP、等待 MQTT、等待 HTTP 请求、等待 WebSocket)已匹配超时
循环循环体、完成上限
其他所有节点输出—

要连接,从一个输出拖到一个节点上;拖放到空画布上,会在那里添加一个新节点。从一个已有接线的输出拖出会再添加一条接线。添加下一步、A 键以及接线上的 + 则把节点插入到现有接线中。

未完成的图是草稿:它会保存,但不会运行。工具栏中的 请补全流程图 说明缺少什么并显示该节点。参见运行前检查的内容。

并行分支 ​

一个输出引出多条接线 ​

当一个输出有多条接线——包括 开始 的——它们所通向的每个节点都同时运行。第一条接线延续该分支;每一条后续接线启动一个并行分支。每个分支都携带自己的变量副本和最近一次 HTTP 响应副本,因此一个分支设置或收到的内容不会被其他分支看到。

并行分支与 Join ​

并行分支 立即通过,并同时从 分支 1 和 分支 2 离开——与一个输出引出两条接线相同,只是画成了一个节点。

汇合分支 等待通向它的每一条接线,然后作为一个分支继续,其副本按这些接线的顺序合并:

  • 它们全部的变量——两条分支都设置的同名值,实验中后列出的接线胜出;
  • 按该顺序,最后一条带来 HTTP 响应的接线的响应;
  • 对于其后的等待节点,它们最近一次动作中最早的那个。

接线的顺序决定一切,绝不取决于哪个分支碰巧先完成。

只 Join 并行运行的分支

Join 会统计它的接线,无论它们是如何变成并行的:来自一个 并行分支、来自一个输出的多条接线、来自不同的路径。分支的 是 和 否 之后只有一条路径运行,因此由两者共同汇入的 Join 会等待一个永远不会到来的分支:运行会以 run.join_waiting 失败,并指出有多少条接线从未被跟随。要把可选路径汇合,请把它们直接接到下一个节点。

被两条并行分支到达的非 Join 节点,会为它们各运行一次。

当步骤失败时 ​

第一个失败使运行失败。其他分支不会开始新步骤:重复或负载提前结束,它们正在进行的任何其他步骤会运行到结束。它们期间遇到的一次失败会在时间线中报告,但不是本次运行的错误。在有 超时 接线的情况下遇到超时的步骤没有失败——参见等待。

分支 ​

节点何时从 是 离开
按状态分支此路径上最近一次 HTTP 响应的状态为给定状态
按值分支其比较成立——参见比较值

否则各自从 否 离开。状态分支在每条路径上都需要它之前有一个 HTTP 请求;按值分支需要它读取的名称在那里已知。当 是 和 否 之后的路径再次汇合时,汇合处的节点只运行一次,且在那里只已知两条路径都设置的变量(变量在哪里可见)。

重试 ​

发送或监听的步骤可以在失败时再试:在其属性中开启 失败时重试。

设置内容范围初始值
尝试次数总共尝试次数,包括第一次1–103
暂停(ms)第二次尝试前的暂停0–60 000 ms500
暂停方式固定:每次暂停相同;倍增:每次暂停是上一次的两倍—固定
  • 重试适用于 HTTP 请求、TCP 消息、 MQTT 发布、OSC 消息、UDP 数据报、 WebSocket 连接、WebSocket 发送 以及所有等待节点。其他 节点拒绝它(node.retry_unsupported),处于 负载下的 HTTP 请求不接受重试。
  • 无论翻倍后是多少,单次暂停都不超过 60 s。
  • 每次失败的尝试都会在时间线中显示为 重试中,带其 次数和原因。步骤随后通过,或以最后一次尝试的原因失败。
  • 只有执行被重复。模板无法解析的字段会立即 失败。
  • 等待回复的发送会再次发送。等待节点再次等待,像之前一样 从分支上最近一次动作起计数。
  • 带有 超时 接线的等待节点不会因超时而失败,因此 不会被重试:它沿 超时 继续。
  • 停止会立即结束暂停。

重复 ​

发送的步骤可以反复发送——心跳、轮询、稳定流——而无需在图中有循环:开启 重复发送。

设置内容范围初始值
重复指定次数 或 指定时长—指定次数
次数总共发送次数,包括第一次2–10 00010
时长(ms)从第一次发送起持续发送多久1–300 000 ms10 000
间隔(ms)两次发送之间的暂停10–60 000 ms1000
抖动(ms)每次暂停随机延长至多此值0–60 000 ms0
  • 重复适用于 HTTP 请求、TCP 消息、 MQTT 发布、OSC 消息、UDP 数据报 和 WebSocket 发送(其他位置为 node.repeat_unsupported)。HTTP 请求要么重复,要么负载,不能两者兼有。
  • 每次发送都像单次发送那样进行:其模板会被重新读取—— {{counter}} 是发送的编号,{{now}} 是其时间——重试开启时 适用于每次发送。等待回复的发送等待自己那一次。
  • 按时间重复时,只有当一次发送能在时间结束前开始时才会发出。
  • 抖动从本次运行的种子中抽取:相同的种子给出相同的 暂停。
  • 时间线最多每秒一次将进度报告为 重复中。 步骤在最后一次发送后以该次发送的结果通过;彻底失败的发送使步骤失败。
  • 另一个分支的失败会结束发送;停止会立即结束暂停。

它必须能放进一次运行:发送次数及其最长暂停 ((count − 1) × (interval + jitter))合计最多 300 s(node.repeat_too_long), 按时间重复最多发送 10 000 次(node.repeat_too_many)。

循环 ​

循环 反复运行其 循环体 输出上的步骤;其中最后一个接回循环节点。

设置内容范围
最多迭代次数最多迭代次数1–1000
满足条件时提前停止退出条件:值、条件、预期值,与 检查值 中相同可选
  1. 从外部到达时,循环节点在 循环体 上开始第 1 次迭代。
  2. 每次循环体返回时读取退出条件——在迭代之后,因此循环体 至少运行一次,并能设置它要测试的内容。
  3. 条件成立时,循环节点从 完成 离开。
  4. 否则开始下一次迭代,只要还有剩余。
  5. 迭代次数先用尽时,如果 上限 已接线,循环节点从它离开, 否则以 loop.limit 使运行失败。没有条件时,循环体运行每一次迭代, 循环节点从 完成 离开。

在循环体内部,{{counter}} 是迭代的编号,因为每个节点 统计自己的执行次数。条件和 完成 或 上限 之后的步骤 可以使用循环体每次迭代都设置的内容——例如循环体提取的状态; 循环体本身只能看到到达循环节点时已知的内容。

模板 轮询直到就绪 每 0.3 s 向设备询问其状态,直到它应答 ready,最多 10 次。

循环体可以包含什么 ​

循环体作为一个分支运行,一次迭代接一次迭代。接回循环节点的接线是实验唯一可以有的环;其他任何环都是 graph.cycle。

规则错误
循环体 上的内容接回循环节点loop.no_return
循环体中的每个输出只有一条接线loop.body_parallel
循环体中的每个输出都继续留在循环体中或接回循环节点loop.body_leaves
只有循环节点的 循环体 输出通向循环体loop.body_entered
循环体中不能有 开始、结束、并行分支、汇合分支 或其他 循环loop.body_unsupported

等待 ​

等待节点在所等待的消息到达时通过: 等待 OSC、等待 UDP、等待 MQTT、 等待 HTTP 请求 和 等待 WebSocket。每个匹配什么见 节点参考;这里说明它们如何监听。

从开始就监听 ​

运行在其第一个步骤之前就打开其等待节点所监听的内容,因此比下一个步骤更快的回复不会被错过:

等待在第一个步骤之前打开
OSC、UDP每个 监听于(IP:端口) 地址一个 UDP 套接字,由使用该地址的每个等待节点共用
HTTP 请求每个地址一个监听器——有本次运行的 HTTP 模拟器 时就是它,否则是一个以 204 应答的监听器
MQTT每个代理和主题过滤器一个连接,已订阅;代理随后重放的保留消息会被忽略
WebSocket什么都没有:它读取 WebSocket 连接 运行时打开的连接

因为它们最先打开,这些地址在运行前就已固定:OSC、 UDP 或 HTTP 等待节点监听字面的 IP:port,端口不能为 0,MQTT 等待节点的代理和主题只接受参数。无法打开的端口——被 占用,或不是本机的地址——会在任何流量之前、在该等待节点的字段处停止运行。运行以任何方式结束时,一切都会关闭。

哪些消息计数 ​

等待节点考虑的是在其分支上最近一次动作开始之后到达的消息——最近一次请求、消息、发布、WebSocket 连接或 发送——或者在没有任何动作之前,运行开始之后到达的消息。请求之前的消息不计数,请求与等待之间的延时或日志不会隐藏其回复。Join 之后,合并分支中最早的那个最近动作计数。

等待节点取第一个匹配的消息并消费它:两个等待节点绝不会 匹配同一条消息。

每个套接字、订阅或连接为其等待节点最多保留 1024 条消息和 64 MiB;超过后,最旧的会被丢弃并计数。

超时 ​

超时(ms) 为 1–120 000 ms,初始为 2000。当时间内没有任何匹配时:

  • 有 超时 接线时,等待节点沿它继续;
  • 没有时,步骤以 wait.timeout 失败,它说明期间还到达了多少条其他 消息——错误的模式与设备沉默看起来不同——并在其详情中说明队列满时丢弃了多少条更旧的消息。

等待节点的变量——reply,HTTP 为 request——只在 已匹配 之后存在。当 检查器 正在捕获时,步骤 还会链接它匹配到的帧:参见时间线。

同一步骤上的回复 ​

OSC 消息 或 UDP 数据报 可以等待自己的应答:开启 等待回复。

设置内容初始值
接收回复于(IP:端口)等待应答的地址;端口 0 表示任意空闲端口0.0.0.0:0
回复地址模式(OSC)、回复载荷(UDP)应答必须是什么,与匹配等待节点中相同任意
超时(ms)1–120 000 ms2000
回复变量应答写入的变量reply

接收回复于(IP:端口) 上的套接字像等待节点的一样在第一个步骤之前打开,消息从它发出:向发送方自身端口应答的设备能被听到,向固定端口应答的设备在该端口正是给定端口时能被听到。步骤在收到匹配的应答后通过,变量在其输出之后存在。没有 超时 输出:时间内没有应答会使步骤失败,重试可以再次发送。要按沉默分支,请使用单独的等待节点。

运行前检查的内容 ​

编辑器在您编辑时检查实验;运行按钮会再检查一次。问题会指出节点,有字段时也指出字段。

规则错误
实验有名称doc.name_required
1–64 个节点,恰好一个 Start 和一个 Enddoc.node_count、doc.start_end_count
Start 没有输入graph.start_input
接线通向另一个存在的节点doc.connection_invalid
同一条接线不会出现两次doc.connection_duplicate
每个必须接线的输出都已接线graph.outputs_required
节点在它没有的输出上没有接线graph.port_unexpected
每个节点都能从 Start 到达graph.unreachable
除了 Loop 接回的接线外没有环graph.cycle,以及循环体规则
检查或 Extract 在每条路径上其之前都有 HTTP 请求;负载下的请求不计数graph.needs_http
每个模板都能解析,且它使用的每个名称在每条路径上都已知template.*、name.*——参见数据
每个字段都存在且在范围内node.*
引用另一个节点的节点——更改损伤、模拟器停机/恢复、WebSocket 节点——引用了一个存在的节点,且 WebSocket 节点在其 connect 之后impair.relay_unknown、emulator.node_unknown、ws.connection_unknown、ws.connection_after
本次运行的两个套接字不共用端口参见故障

然后运行会检查它开始所需的条件:每个机密已存储,每个端口已打开。在一切成立之前,不会运行任何步骤,也不会发送任何内容。

时间限制 ​

一次运行最多持续 300 s。届时仍在进行的会被停止并以 run.timeout 失败。从命令行和 API 可以设置更短的限制,1–300 s。

停止 ​

运行进行期间,运行按钮是 停止。停止会立即结束运行:每个分支、重试或重复的每次暂停、每个等待和每个负载——在途的请求会被放弃。它的套接字、订阅、模拟器和中继会关闭,其 WebSocket 连接会发送关闭帧。顶栏中的 全部停止 对每个任务做同样的事。被停止的运行不保存报告;参见运行。