Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -405,17 +405,22 @@ SPACETIMEDB_CLIENT_DISCONNECTED(on_disconnect, ReducerContext ctx) { /* ... */ }

```typescript
const reminder = table(
{ name: 'reminder', scheduled: (): any => send_reminder },
{ name: 'reminder' },
{
id: t.u64().primaryKey().autoInc(),
message: t.string(),
scheduled_at: t.scheduleAt(),
}
);

export const send_reminder = spacetimedb.reducer({ arg: reminder.rowType }, (ctx, { arg }) => {
console.log(`Reminder: ${arg.message}`);
});
// `onSchedule` binds the reducer to the schedule table
export const send_reminder = spacetimedb.reducer(
{ onSchedule: reminder },
{ arg: reminder.rowType },
(ctx, { arg }) => {
console.log(`Reminder: ${arg.message}`);
}
);
```

</TabItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -559,7 +559,7 @@ import { schema, t, table } from 'spacetimedb/server';

// Define a schedule table for the procedure
const fetchSchedule = table(
{ name: 'fetch_schedule', scheduled: (): any => fetchExternalData },
{ name: 'fetch_schedule' },
{
scheduledId: t.u64().primaryKey().autoInc(),
scheduledAt: t.scheduleAt(),
Expand All @@ -570,8 +570,10 @@ const fetchSchedule = table(
const spacetimedb = schema({ fetchSchedule });
export default spacetimedb;

// The procedure to be scheduled
// The procedure to be scheduled, bound to the schedule table with `onSchedule`.
// A scheduled procedure must return `t.unit()`.
export const fetchExternalData = spacetimedb.procedure(
{ onSchedule: fetchSchedule },
{ arg: fetchSchedule.rowType },
t.unit(),
(ctx, { arg }) => {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -325,7 +325,7 @@ Scheduled reducers and procedures are private by default in SpacetimeDB 2.x, so
import { schema, table, t } from 'spacetimedb/server';

const scheduledTask = table(
{ name: 'scheduled_task', scheduled: (): any => sendReminder },
{ name: 'scheduled_task' },
{
taskId: t.u64().primaryKey().autoInc(),
scheduledAt: t.scheduleAt(),
Expand All @@ -336,9 +336,13 @@ const scheduledTask = table(
const spacetimedb = schema({ scheduledTask });
export default spacetimedb;

export const sendReminder = spacetimedb.reducer({ arg: scheduledTask.rowType }, (_ctx, { arg }) => {
console.log(`Reminder: ${arg.message}`);
});
export const sendReminder = spacetimedb.reducer(
{ onSchedule: scheduledTask },
{ arg: scheduledTask.rowType },
(_ctx, { arg }) => {
console.log(`Reminder: ${arg.message}`);
}
);
```

</TabItem>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import { CppModuleVersionNotice } from "@site/src/components/CppModuleVersionNot
Tables can trigger [reducers](../00200-functions/00300-reducers/00300-reducers.md) or [procedures](../00200-functions/00400-procedures.md) at specific times by including a special scheduling column. This allows you to schedule future actions like sending reminders, expiring items, or running periodic maintenance tasks.

:::tip Scheduling Procedures
Procedures use the same scheduling pattern as reducers. Simply reference the procedure name in the `scheduled` attribute. This is particularly useful when you need scheduled tasks that make HTTP requests or perform other side effects. See [Scheduling Procedures](../00200-functions/00300-reducers/00300-reducers.md#scheduling-procedures) for an example.
Procedures use the same scheduling pattern as reducers: pass the `onSchedule` option in TypeScript, or reference the procedure name in the `scheduled` attribute in other languages. This is particularly useful when you need scheduled tasks that make HTTP requests or perform other side effects. See [Scheduling Procedures](../00200-functions/00300-reducers/00300-reducers.md#scheduling-procedures) for an example.
:::

## Defining a Schedule Table
Expand All @@ -23,6 +23,40 @@ The table attribute uses `scheduled` (with a "d") because it refers to the **sch
<Tabs groupId="server-language" queryString>
<TabItem value="typescript" label="TypeScript">

In TypeScript, declare the binding on the reducer with the `onSchedule` option:

```typescript
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 }) => {
// Invoked automatically by the scheduler
// arg.message, arg.scheduledAt, arg.scheduledId
}
);
```

`onSchedule` registers the reducer as the schedule table's target. Because the table definition does not reference the reducer, the table and the reducer can live in separate files without a circular import. A schedule table can be bound to at most one reducer or procedure; binding a second one is a schema error.

The same option works on procedures, provided the procedure's return type is `t.unit()`. See [Scheduling Procedures](../00200-functions/00300-reducers/00300-reducers.md#scheduling-procedures).

:::note Legacy `scheduled` table option
Older code declares the binding on the table instead, using a thunk that forward-references the scheduled reducer:

```typescript
const reminder = table(
{ name: 'reminder', scheduled: (): any => sendReminder },
Expand All @@ -35,10 +69,12 @@ const reminder = table(

export const sendReminder = spacetimedb.reducer({ arg: reminder.rowType }, (_ctx, { arg }) => {
// Invoked automatically by the scheduler
// arg.message, arg.scheduledAt, arg.scheduledId
});
```

This form still works, but the forward reference forces the table and reducer into the same file and defeats type inference (hence the `(): any =>` cast). Prefer `onSchedule` in new code.
:::

</TabItem>
<TabItem value="csharp" label="C#">

Expand Down
Loading