Realtime Subscriptions
The Rust SDK supports live queries over a shared WebSocket connection.
Ownership boundary:
link-commonowns the shared connection, reconnect loop, replay filtering, andSeqIdcheckpoint tracking.- Your app owns the async loop over
live.next()orevents.next().
Live SQL must follow the strict supported shape: SELECT ... FROM ... WHERE ....
Do not include ORDER BY or LIMIT in live subscription SQL. Apply ordering or row caps in application code after rows arrive, or use LiveRowsConfig::limit.
Call client.connect().await? before opening subscriptions so they multiplex over one socket (unless you rely on lazy connect on first subscription).
Which API to use
| API | Use when |
|---|---|
live() / live_with_config() | You want the current materialized row list (recommended for UI and most services) |
live_events() / live_events_with_config() | You need raw ChangeEvent frames for custom reconciliation or debugging |
Unlike execute_query, live APIs take the final SQL string directly — there is no separate params argument. Embed constants in the WHERE clause or use separate subscriptions per filter.
Materialized live rows
Shorthand when defaults are enough:
Control knobs
| Knob | Layer | Effect |
|---|---|---|
with_batch_size(n) | Server snapshot | Chunks initial rows from the server |
with_last_rows(n) | Server rewind | How much history to fetch on connect |
LiveRowsConfig { limit: Some(n), .. } | Client materializer | Caps rows kept in memory after reconciliation |
with_from(seq_id) | Resume | Continue from a persisted SeqId |
Each LiveRowsEvent::Rows includes last_seq_id for durable checkpoints.
Low-level change events
Inspect active subscriptions
Cancel one explicitly:
Topic consumers (optional)
Topic workers are behind the consumer feature — not a separate crate.
kalam-client = { version = "0.8.0", features = ["native-sdk", "consumer"] }Full walkthrough: Topic Consumer example.
Next
SHARED table ownership and resume domains
Clustered servers default to shared_shards = 4. Each SHARED table owns exactly one Raft group. CREATE persists table_options.shared_shard_id and a fresh history_incarnation in replicated table metadata. Increasing the configured count places new tables across the expanded set; existing owners do not change. Do not remove a shard that owns tables. Legacy metadata without an owner stays on shard 0. Moving existing data requires explicit export/import into a fresh history.
_version = (raft_log_index << 16) | ordinal is ordered only within its table’s domain. Different tables on the same shard can interleave, so per-table versions can have gaps. Transactions spanning different owner groups are rejected.
A SHARED subscription acknowledgement includes batch_control.version_domain with history_incarnation, table_id, scope_id (the shared owner), and partition_id (currently null). Persist this complete envelope together with the last safely consumed version. Resume by supplying both options.from and options.version_domain. Missing envelopes, another table/group/history, and unsupported partitions are rejected as stale cursors. Take a fresh snapshot after CURSOR_EXPIRED; do not reuse the old domain.
The Rust transport preserves the acknowledgement domain for automatic reconnect. In TypeScript, use versionDomain with from when restoring a persisted checkpoint; it serializes as version_domain. Treat the domain as opaque and never infer it from the numeric version.