diff --git a/.changeset/fresh-rockets-marry.md b/.changeset/fresh-rockets-marry.md new file mode 100644 index 0000000..731251b --- /dev/null +++ b/.changeset/fresh-rockets-marry.md @@ -0,0 +1,5 @@ +--- +"partyserver": patch +--- + +implement onAlarm diff --git a/packages/partyserver/README.md b/packages/partyserver/README.md index 0b36a06..9473d00 100644 --- a/packages/partyserver/README.md +++ b/packages/partyserver/README.md @@ -110,6 +110,8 @@ These methods can be optionally `async`: - `onRequest(request): Response` - Called when a request is made to the server. This is useful for handling HTTP requests in addition to WebSocket connections. +- `onAlarm()` - Called when an alarm is triggered. You can set an alarm by calling `this.ctx.storage.setAlarm(Date)`. Read more about Durable Objects alarms [here](https://developers.cloudflare.com/durable-objects/api/alarms/). + - `getConnectionTags(connection, context): string[]` - You can set additional metadata on connections by returning them from `getConnectionTags()`, and then filter connections based on the tag with `this.getConnections`. ### Additional Methods @@ -132,9 +134,9 @@ These methods can be optionally `async`: - `fetch(request)` - PartyServer overrides the `fetch` method to add the lifecycle methods to the server instance. In most cases you don't have to implement this mehod yourself. If you do (for example, to add request handling before any lifecycle methods are called), make sure to call `super.fetch(request)` as appropriate to ensure the lifecycle methods are called. -- `alarm()` - Implement this method to handle alarms. This is the only way to run code after the server has been evicted. Read more about alarms [here](https://developers.cloudflare.com/durable-objects/api/alarms/). +- `alarm()` - _You should not implement/override this yourself, use `onAlarm()` instead._ This method is called whenever an alarm is triggered. This is the only way to run code after the server has been evicted. Read more about alarms [here](https://developers.cloudflare.com/durable-objects/api/alarms/). -- Do not implement any of these methods on your server class: `webSocketMessage` /`webSocketClose` / `webSocketError`. We override them to call the lifecycle methods in hibernation mode. +- Do not implement any of these methods on your server class: `webSocketMessage` /`webSocketClose` / `webSocketError` / alarm. We override them to call the lifecycle methods in hibernation mode. ### Connection Properties diff --git a/packages/partyserver/src/index.ts b/packages/partyserver/src/index.ts index 8510c44..b2ceaec 100644 --- a/packages/partyserver/src/index.ts +++ b/packages/partyserver/src/index.ts @@ -178,7 +178,7 @@ export class Server extends DurableObject { // TODO: throw error if any of // broadcast/getConnection/getConnections/getConnectionTags - // fetch/webSocketMessage/webSocketClose/webSocketError + // fetch/webSocketMessage/webSocketClose/webSocketError/alarm // have been overridden } @@ -193,7 +193,8 @@ export class Server extends DurableObject { const namespace = request.headers.get("x-partykit-namespace"); const room = request.headers.get("x-partykit-room"); if (!namespace || !room) { - throw new Error("Missing namespace or room headers"); + throw new Error(`Missing namespace or room headers when connecting to ${this.#ParentClass.name}. +Did you try connecting directly to this Durable Object? Try using getServerByName(namespace, id) instead.`); } await this.setName(room); } @@ -520,4 +521,19 @@ export class Server extends DurableObject { return new Response(`Not implemented`, { status: 404 }); } + + onAlarm(): void | Promise { + console.log( + `Implement onAlarm on ${this.#ParentClass.name} to handle alarms.` + ); + } + + async alarm(): Promise { + if (this.#status !== "started") { + // This means the server "woke up" after hibernation + // so we need to hydrate it again + await this.#initialize(); + } + await this.onAlarm(); + } }