-
Notifications
You must be signed in to change notification settings - Fork 1k
docs: update automatic migration compatibility notes #5723
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
885222e
0cb7a81
69db31e
ecfd480
8c6601b
273e661
597dcaf
c7cca2b
13a25dd
aa1d865
75e00a6
836b027
c70390e
5cf912c
cd53f8a
8dce5c1
64ac393
f18197c
478f3fd
80637dd
7919cfa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -32,6 +32,8 @@ These changes are allowed by automatic migration, but may cause runtime errors f | |
| - **Adding new columns to the end of a table with a default value.** The new column must be added at the end of the table definition and must have a default value specified. Non-updated clients will not be aware of the new column. | ||
| - **Changing or removing reducers.** Clients attempting to call the old version of a changed reducer or a removed reducer will receive runtime errors. | ||
| - **Changing tables from public to private.** Clients subscribed to a newly-private table will receive runtime errors. | ||
| - **Changing table or column accessor names while preserving canonical names.** The stored data can be migrated, but source code that refers to the old accessors must be updated. This may also change generated index names shown in SQL or migration output, even when an index's accessor and canonical name are unchanged. | ||
| - **Removing empty tables.** SpacetimeDB can remove a table only if it has no rows. Removing a table disconnects active clients. Clients using bindings or subscription queries generated from the old schema must be updated before reconnecting, because the removed table no longer exists. | ||
| - **Removing `Primary Key` annotations.** Non-updated clients will still use the old primary key as a unique key in their local cache, which can result in non-deterministic behavior when updates are received. | ||
| - **Removing indexes.** This is only breaking in specific situations. The main issue occurs with subscription queries involving semijoins, such as: | ||
|
|
||
|
|
@@ -48,12 +50,13 @@ These changes are allowed by automatic migration, but may cause runtime errors f | |
|
|
||
| The following changes cannot be performed with automatic migration and will cause the publish to fail: | ||
|
|
||
| - **Removing tables.** | ||
| - **Removing or modifying existing columns.** This includes changing the type, renaming, or reordering columns. | ||
| - **Removing non-empty tables.** Empty tables can be removed automatically, but table removal fails if the existing table contains rows. | ||
| - **Removing or modifying existing columns.** This includes changing the type, canonical name, or order of columns. Changing only the generated accessor alias is allowed, but source code that refers to the old accessor must be updated. | ||
| - **Adding columns without a default value.** New columns must have a default value so existing rows can be populated. | ||
| - **Adding columns in the middle of a table.** New columns must be added at the end of the table definition. | ||
| - **Changing whether a table is used for `scheduling`.** | ||
| - **Adding `Unique` or `Primary Key` constraints.** This could result in existing tables being in an invalid state. | ||
| - **Changing an index accessor name.** Create a new index accessor instead of renaming an existing one. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Can you clarify this a bit? I'm not clear on what it means. How do you create a new accessor name? |
||
|
|
||
| ## Working with Forbidden Changes | ||
|
|
||
|
|
@@ -91,6 +94,7 @@ For complex schema changes that aren't supported by automatic migration: | |
| During automatic migrations, active client connections are maintained and subscriptions continue to function. However: | ||
|
|
||
| - Clients may witness brief interruptions in scheduled reducers (such as game loops) | ||
| - Some migrations, such as removing a table, disconnect active clients so they reconnect against the new schema | ||
| - New module versions may remove or change reducers, causing runtime errors for clients calling those reducers | ||
| - Clients won't automatically know about schema changes - you may need to regenerate and update client bindings | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -257,7 +257,7 @@ SPACETIMEDB_REDUCER(update_score, ReducerContext ctx, uint32_t new_score) { | |
| The connection ID identifies the specific client connection that invoked the reducer. This is useful for tracking sessions or implementing per-connection state. | ||
|
|
||
| :::note | ||
| The connection ID may be absent for reducers invoked by the system (such as scheduled reducers or lifecycle reducers) or when called via the CLI without specifying a connection. In TypeScript modules, `ctx.connectionId` is `ConnectionId | null`. | ||
| The connection ID may be absent for reducers invoked without a client connection, such as `init`, scheduled reducers, or CLI calls without an explicit connection. Client-connected and client-disconnected reducers receive the connection ID for the connection being opened or closed. In TypeScript modules, `ctx.connectionId` is still typed as `ConnectionId | null`, so shared helper code should handle the nullable type. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't really understand the motivation for this change. |
||
| ::: | ||
|
|
||
| ### Timestamp | ||
|
|
@@ -324,7 +324,7 @@ Scheduled reducers and procedures are private by default in SpacetimeDB 2.x, so | |
| ```typescript | ||
| import { schema, table, t } from 'spacetimedb/server'; | ||
|
|
||
| const scheduledTask = table( | ||
| const scheduled_task = table( | ||
| { name: 'scheduled_task' }, | ||
| { | ||
| taskId: t.u64().primaryKey().autoInc(), | ||
|
|
@@ -333,12 +333,12 @@ const scheduledTask = table( | |
| } | ||
| ); | ||
|
|
||
| const spacetimedb = schema({ scheduledTask }); | ||
| const spacetimedb = schema({ scheduled_task }); | ||
| export default spacetimedb; | ||
|
|
||
| export const sendReminder = spacetimedb.reducer( | ||
| { onSchedule: scheduledTask }, | ||
| { arg: scheduledTask.rowType }, | ||
| { onSchedule: scheduled_task }, | ||
| { arg: scheduled_task.rowType }, | ||
| (_ctx, { arg }) => { | ||
| console.log(`Reminder: ${arg.message}`); | ||
| } | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -176,6 +176,8 @@ To schedule an action, insert a row into the schedule table with a `scheduled_at | |
| - **At intervals** - Execute repeatedly at fixed time intervals (e.g., every 5 seconds) | ||
| - **At specific times** - Execute once at an absolute timestamp | ||
|
|
||
| Interval schedules are anchored to their intended execution times. If the database is busy or offline long enough to miss one or more interval ticks, SpacetimeDB schedules the next future tick rather than running missed ticks back-to-back or drifting the schedule from the delayed execution time. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This is accurate to what happens now, but we may decide to change it to run missed ticks back-to-back in the future. |
||
|
|
||
| ### Scheduling at Intervals | ||
|
|
||
| Use intervals for periodic tasks like game ticks, heartbeats, or recurring maintenance: | ||
|
|
@@ -405,6 +407,8 @@ ctx.db[reminder].insert(Reminder{ | |
| 3. **When the time arrives**, the specified reducer/procedure is automatically called with the row as a parameter | ||
| 4. **The row is typically deleted** or updated by the reducer after processing | ||
|
|
||
| For interval schedules, the next run is calculated from the previous intended run time. Missed interval ticks are skipped, so a delayed scheduled reducer or procedure resumes on the next future interval boundary. | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. You've for sure verified this is the case? |
||
| ### Row Lifecycle | ||
|
|
||
| SpacetimeDB passes the schedule row to the scheduled reducer or procedure as an argument. One-shot schedule rows are removed at different times depending on the kind of function being called: | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Generated index names are shown in SQL? What? That doesn't sound right. Also what is "migration output"?