news 2026/9/13 17:01:46

如何用 SpacetimeDB 计划表让 Reducer 在指定时间或按间隔定时执行

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
如何用 SpacetimeDB 计划表让 Reducer 在指定时间或按间隔定时执行

如何用 SpacetimeDB 计划表让 Reducer 在指定时间或按间隔定时执行

【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB

SpacetimeDB 的模块中,Reducer 是修改数据库状态的唯一途径,但 Reducer 默认只能被客户端或系统事件触发,无法自己“在某个时间醒来”执行。计划表(Schedule Table)解决的就是这个问题:在表中包含一个特殊的调度列(ScheduleAt类型),SpacetimeDB 就会监视这张表,并在时间到达时自动调用你绑定的 Reducer,参数就是这张表的一行。本文以 TypeScript 模块为例,走一遍“定义计划表 → 绑定 Reducer → 插入定时行 → 调用并验证执行”的完整流程,适用前提是本机已安装 SpacetimeDB CLI 和 Node.js 18+。

准备工作:启动本地服务器与 TypeScript 模块

先安装spacetimeCLI(参考 Getting Started),然后创建项目并启动本地 Standalone 服务器:

spacetime dev --template basic-ts

这条命令会同时启动本地 SpacetimeDB 服务器、发布你的模块并生成客户端绑定,服务器默认监听3000端口。模块的服务器端代码位于spacetimedb/src/index.ts,下面的修改都在这一个文件里完成。

定义计划表并绑定要定时执行的 Reducer

计划表是一张普通表,但其中必须包含一个ScheduleAt类型的列,用来声明“什么时候执行”。用onSchedule选项把 Reducer 绑定到这张表:

import { ScheduleAt } from 'spacetimedb'; import { schema, table, t } from 'spacetimedb/server'; const reminder = table( { name: 'reminder' }, { scheduledId: t.u64().primaryKey().autoInc(), scheduledAt: t.scheduleAt(), message: t.string(), } ); const spacetimedb = schema({ reminder }); export default spacetimedb; export const sendReminder = spacetimedb.reducer( { onSchedule: reminder }, { arg: reminder.rowType }, (_ctx, { arg }) => { console.info(`Scheduled reminder fired: ${arg.message}`); } );

几个必须注意的点:

  • 文档特别强调:ScheduleAt类要从'spacetimedb'导入,不是'spacetimedb/server';表列类型则用t.scheduleAt()
  • onSchedule在 Reducer 上声明绑定,因此计划表和 Reducer 可以放在不同文件里,不会产生循环导入。
  • 一张计划表最多只能绑定一个 Reducer 或 Procedure,再绑定第二个是 schema 错误。
  • 旧代码也可能在表定义里写scheduled: () => sendReminder(带 thunk 的前向引用),这种写法仍然有效,但会强制表和函数写在同一文件并破坏类型推断,新代码建议用onSchedule

如果你用其他语言写服务器模块,绑定方式不同:Rust 在表上使用#[table(..., scheduled(send_reminder))],字段类型为ScheduleAt;C# 使用[SpacetimeDB.Table(..., Scheduled = "SendReminder", ScheduledAt = "ScheduledAt")],其中ScheduledAt的值必须精确等于表中某个ScheduleAt类型字段的字段名;C++ 使用SPACETIMEDB_SCHEDULE(reminder, 1, send_reminder),第二个参数是scheduled_at列的 0 起始下标。完整示例见 Schedule Tables。

插入 ScheduleAt 行:间隔执行与指定时间执行

向计划表插入一行即完成一次“排程”,ScheduleAt有两种取值方式,对应标题中的两种场景。

按间隔重复执行(interval)

适合游戏 tick、心跳、周期性维护等任务。TypeScript 中ScheduleAt.interval(...)的参数单位是微秒

export const schedulePeriodicTasks = spacetimedb.reducer((ctx) => { // 每 5 秒执行一次(5,000,000 微秒) ctx.db.reminder.insert({ scheduledId: 0n, scheduledAt: ScheduleAt.interval(5_000_000n), message: "Check for updates", }); // 每 100 毫秒执行一次 ctx.db.reminder.insert({ scheduledId: 0n, scheduledAt: ScheduleAt.interval(100_000n), // 100ms 换算成微秒 message: "Game tick", }); });

scheduledId0n,因为列声明了autoInc(),实际主键由数据库自动分配。Rust 中等价的间隔写法用Duration表达:

ctx.db.reminder().insert(Reminder { scheduled_id: 0, message: "Check for updates".to_string(), scheduled_at: ScheduleAt::Interval(Duration::from_secs(5).into()), });

关于错过的 tick:文档说明 interval 调度锚定在“原本计划的执行时刻”上。如果数据库繁忙或离线导致错过了一个或多个间隔 tick,SpacetimeDB 会排定下一个未来的 tick,而不是把错过的 tick 连续补跑,也不会以延迟后的执行时间为基准重新漂移。

在指定时间一次性执行(time)

适合“某个时刻发送提醒”“内容到期失效”这类单次动作。时间戳是“自 Unix 纪元起的微秒数”,可以用ctx.timestamp相对计算,也可以给绝对时间戳:

export const scheduleTimedTasks = spacetimedb.reducer((ctx) => { // 10 秒后执行 const tenSecondsFromNow = ctx.timestamp.microsSinceUnixEpoch + 10_000_000n; ctx.db.reminder.insert({ scheduledId: 0n, scheduledAt: ScheduleAt.time(tenSecondsFromNow), message: "Your auction has ended", }); // 指定绝对 Unix 时间戳(微秒):1735689600_000_000n 是文档给出的 2025-01-01 00:00:00 UTC const targetTime = 1735689600_000_000n; ctx.db.reminder.insert({ scheduledId: 0n, scheduledAt: ScheduleAt.time(targetTime), message: "Happy New Year!", }); });

Rust 中可以用ctx.timestamp + Duration::from_secs(10)计算 10 秒后的时刻,也可以把ScheduleAt::Time(ctx.timestamp.clone())作为“立即执行”的排程值(文档示例)。C# 侧则使用new ScheduleAt.Time(DateTimeOffset)ctx.Timestamp + new TimeDuration(10_000_000)(微秒)。

验证定时 Reducer 是否按时执行

模块代码保存后spacetime dev会自动重新发布。在另一个终端进入项目目录,调用上面定义的触发 Reducer 把定时行写入计划表:

spacetime call schedulePeriodicTasks

然后观察模块日志:

spacetime logs

如果 interval 排程生效,你会看到被调度的 Reducer 体内的日志按间隔周期性出现。以 Rust 示例为例,文档给出的send_reminder会在每次 tick 时执行,init里插入的 50ms 间隔行让它在模块发布后立即开始按 tick 运行。spacetime logs的具体输出内容因你的 Reducer 代码而异,文档中展示的INFO: Hello, Alice!这类行是 TypeScript 快速上手示例的输出,只说明日志查看方式,不是计划表的固定输出。

定时行的生命周期:执行前还是执行后删除?

这一点直接决定你能否在被调度的函数里回查这行数据:

  • 被调度的 Procedure:行在执行前被删除,所以执行期间schedule_table.find(scheduled_id)返回null.update()会失败。
  • 被调度的 Reducer:行在执行后被删除,所以 Reducer 运行期间这行在计划表里仍然可见。
  • interval 调度行永远不会被自动删除。只有 one-shot(指定时间)行在跑完后才移除,interval 行需要你自己处理(例如不再需要时删除),否则它会一直按间隔触发。

可选分支:调度 Procedure 而不是 Reducer

Reducer 运行在隔离环境里,不能发网络请求、不能访问文件系统。如果定时任务需要产生数据库之外的副作用(比如定时发起 HTTP 请求),把同一套排程模式用在 Procedure 上即可:TypeScript 中用spacetimedb.procedure({ onSchedule: fetchSchedule }, ...),且 Procedure 的返回类型必须是t.unit();Rust 中在表上写scheduled(fetch_external_data)。详细示例见 Reducers 文档的 Scheduling Procedures 一节。

限制与适用边界

  • 绑定关系是一张计划表对一个 Reducer 或 Procedure,重复绑定是 schema 错误。
  • interval 行不会自动删除,清理责任在你;one-shot 行按上文规则在 Procedure 执行前、Reducer 执行后删除。
  • 错过 interval tick 时只跳到下一个未来边界,不会补跑,也不以延迟后的时刻为锚点。
  • C++ 模块的排程写法见 Schedule Tables 中的 C++ 选项卡,注意其SPACETIMEDB_SCHEDULE的列下标从 0 开始计数。

完成上述步骤后,如果你的 Reducer 日志按预期出现,说明计划表链路已经打通;需要对外提供定时数据的实时推送时,下一步可以看 Subscriptions。

【免费下载链接】SpacetimeDBDevelopment at the speed of light项目地址: https://gitcode.com/GitHub_Trending/sp/SpacetimeDB

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

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

TMC电机驱动电流精准匹配三步法:从参数表到电流处方单

1. 这不是芯片参数表,而是一份电机驱动系统的“电流处方单”TMC驱动芯片——这三个字母在步进电机控制领域几乎等同于“静音、平滑、高精度”的代名词。但现实里,我见过太多工程师拿着TMC2209的资料兴奋下单,结果装机后电机一转就抖&#xff…

作者头像 李华
网站建设 2026/9/13 17:00:56

Java+Vue垃圾分类小程序开发实战与架构解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/9/13 16:58:48

手写User-Based协同过滤推荐系统:从稀疏矩阵到前端展示全链路实现

简介:本资源是一套完整的基于Python的协同过滤推荐算法电影推荐系统,专为计算机相关专业本科生毕业设计、课程设计及项目实战学习者打造,有效解决推荐系统原理理解与工程落地脱节问题。压缩包共1197个文件,含22个核心Python源码文…

作者头像 李华
网站建设 2026/9/13 16:58:28

UnoCSS Autocomplete 完全指南:为原子化 CSS 打造智能补全

UnoCSS Autocomplete 完全指南:为原子化 CSS 打造智能补全 【免费下载链接】unocss The instant on-demand atomic CSS engine. 项目地址: https://gitcode.com/GitHub_Trending/un/unocss UnoCSS 的 Autocomplete 是一套面向智能提示的可定制机制&#xff0…

作者头像 李华