Skip to content

Part 3: Clear Idle Rooms

A room nobody uses should forget its messages. Each room has one alarm: a time at which Rivet calls the room again, whether or not anyone else does. Set it on every post, and clear the room when it fires.

src/room.ts
import { Default } from "./cluster.ts";
const IDLE_MS = 60 * 60 * 1000;
src/room.ts
post: (author: string, text: string) =>
Effect.gen(function* () {
yield* (yield* sql.exec(
"INSERT INTO messages (author, text) VALUES (?, ?)",
author,
text,
)).toArray();
const now = yield* Effect.sync(() => Date.now());
yield* state.storage.setAlarm(now + IDLE_MS);
}),

setAlarm takes a time in milliseconds. Setting it again moves it, so the alarm keeps getting pushed back while people talk, and fires an hour after the last post.

src/room.ts
messages: () =>
Effect.gen(function* () {
const rows = yield* sql.exec<{ author: string; text: string }>(
"SELECT author, text FROM messages",
);
return yield* rows.toArray();
}),
alarm: () =>
Effect.gen(function* () {
yield* (yield* sql.exec("DELETE FROM messages")).toArray();
}),
};

alarm isn’t a method callers can run. Rivet calls it when the alarm comes due.

Terminal window
pnpm alchemy deploy

Post a message, then read it back an hour later. The list is empty. The visitor count stays, because it lives in key-value storage, not in the table.

You have rooms that keep a conversation while people talk, and forget it when they leave.