为什么以一次输入为单位
BlockX 的主要计算方式是将许多输入拆成独立的函数调用。一个调用可以处理一条源记录,并进行少量表查询、链上读取或子函数调用;它也可以返回多条记录,不要求输入与输出行数一一对应。 这种划分让平台能够并行处理大量输入,并在等待数据访问时继续执行其他调用。适合放入 Function 的工作通常有明确边界:字段转换、事件解析、对象状态计算等。历史遍历、持续监听和任务编排放在驱动脚本中,跨大量记录的聚合可使用SQL 分析。一次调用如何执行
控制台测试和 OpenAPI 使用同步调用入口,在请求内等待结果。Notebook 还可以将一组调用提交为 Task(计算任务),由 BlockX 调度执行:- 调用方描述输入和计算函数。任务可以直接携带输入,也可以指定从哪些源记录生成调用。
- Worker(执行节点)接收任务,将独立调用分配给本机的 Python 执行器池。同一任务由一个 Worker 管理,多个任务可以分布在不同 Worker 上。
- 执行器运行函数。访问 BlockDB、链上节点或其他 Function 时,SDK 将请求交回 BlockX 处理,再把结果送回函数继续执行。
- 任务直接发起的调用(根调用)全部成功完成后,任务汇总返回值,并执行配置的结果处理器。子函数的返回值先回到父函数,参与父函数的计算。
输入与输出
控制台中的 Python Function 使用_ 作为入口。参数配置定义输入的名称、类型和顺序,调用时按位置与入口参数对应。参数的取值格式见数据类型。
返回值应能表示为 JSON 数据,例如数字、字符串、布尔值、列表、字典或 None。将 SDK 返回的对象转换成所需字段后再返回,不要直接返回表对象、迭代器或客户端实例。
print() 用于记录调试信息;调用方需要使用的数据应通过 return 返回。
独立调用与代码版本
任务内的独立调用没有执行顺序保证。计算时不要依赖“上一条输入已经执行”,也不要用模块全局变量在调用之间累计结果。需要跨调用保留的数据,应由调用方汇总或写入数据表。 同一任务在开始执行时固定所使用的函数代码版本,包含任务内调用的子函数。任务执行中保存新代码,不会让它前半段使用旧代码、后半段使用新代码;新版本可供后续任务使用。 BlockX 可以在任务内合并相同代码与参数的调用、复用返回结果,并对部分失败调用重试。因此,函数应尽量根据显式输入计算结果,不依赖调用次数、当前时间或隐含的可变状态。需要可重复的链上计算时,将区块 ID 作为输入,并将它传给相关数据读取;固定代码版本本身不会固定所读取的数据。运行环境与访问边界
Function 在平台提供的受限 Python 环境中运行,支持业务计算,以及通过 SDK 读取数据、查询链上状态和调用其他 Function。 编写函数时,应按这一运行环境组织代码:- 使用支持的 SDK 读取表、查询链上状态和调用其他 Function,不依赖任意安装的软件包或直接访问操作系统、外部网络。
- Notebook 中定义的计算函数也应自行导入依赖,并通过参数接收数据,避免依赖驱动脚本的全局变量或闭包。
- SDK 在 Notebook 中可用的接口,不代表都能在 Function 中使用。持续订阅、任务提交和运行管理由驱动脚本负责。
调用预算与任务期限
控制台测试、OpenAPI 和任务调用使用不同的时间控制,不能用一个入口的成功判断另一个入口一定成功。
子函数调用共享外层的时间约束,嵌套调用不会获得无限的新预算。对可合并的读取使用批量接口,并按独立输入拆分计算,有助于控制一次调用的耗时。
任务内的调用重试与重新提交整个任务是两件事。BlockX 不自动重跑整个失败任务;调用方应根据任务结果决定后续处理,并考虑已经发生的写入。
计算与结果处理
同一个 Function 可以供不同调用方使用,返回结果后的动作取决于调用方式:
用于 Pipeline 的计算函数通常返回一条记录、记录列表或
None。None 表示不为该输入产生记录;返回记录需要符合目标表结构,由 Pipeline 配置的结果处理器写入。一次 return 只完成计算,并不单独代表目标表写入成功。
任务汇总的返回值不保证与输入顺序一致。如果调用方需要将结果对应回输入,应在返回记录中保留业务 ID。