Skip to content
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

Add optional AlarmInvocationInfo parameter to Durable Object alarm() method #3224

Merged
merged 1 commit into from
Dec 10, 2024
Merged
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
2 changes: 1 addition & 1 deletion src/workerd/api/actor.h
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ class DurableObject final: public Fetcher {

JSG_TS_DEFINE(interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I notice in our index.d.ts files, we define both a DurableObject interface at the top level and a DurableObject abstract class inside the cloudflare:workers module. I think the interface is intended to cover legacy uses of Durable Objects prior to the introduction of the class, and that extending the class is the way we recommend implementing Durable Objects in documentation and tutorials. I'm not sure whether it's important to add the parameter to the interface, or where that gets tested, but I went ahead and added it for completeness.

webSocketMessage?(ws: WebSocket, message: string | ArrayBuffer): void | Promise<void>;
webSocketClose?(ws: WebSocket, code: number, reason: string, wasClean: boolean): void | Promise<void>;
webSocketError?(ws: WebSocket, error: unknown): void | Promise<void>;
Expand Down
2 changes: 1 addition & 1 deletion types/defines/rpc.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,7 @@ declare module "cloudflare:workers" {
constructor(ctx: DurableObjectState, env: Env);

fetch?(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer
Expand Down
4 changes: 2 additions & 2 deletions types/generated-snapshot/2021-11-03/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ interface Cloudflare {
}
interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The changes to types/generated-snapshot/* were all generated by running the command recommended by a CI error message:

  The generated output of @cloudflare/workers-types has been changed by this
  PR. If this is intentional, run:
  bazel build //types && rm -rf types/generated-snapshot && cp -r bazel-bin/types/definitions types/generated-snapshot

I assume it's doing the right thing by regenerating these snapshot files, but I'm not familiar with the intent.

webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down Expand Up @@ -5312,7 +5312,7 @@ declare module "cloudflare:workers" {
protected env: Env;
constructor(ctx: DurableObjectState, env: Env);
fetch?(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
2 changes: 1 addition & 1 deletion types/generated-snapshot/2021-11-03/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ export interface Cloudflare {
}
export interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
4 changes: 2 additions & 2 deletions types/generated-snapshot/2022-01-31/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ interface Cloudflare {
}
interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down Expand Up @@ -5338,7 +5338,7 @@ declare module "cloudflare:workers" {
protected env: Env;
constructor(ctx: DurableObjectState, env: Env);
fetch?(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
2 changes: 1 addition & 1 deletion types/generated-snapshot/2022-01-31/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ export interface Cloudflare {
}
export interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
4 changes: 2 additions & 2 deletions types/generated-snapshot/2022-03-21/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ interface Cloudflare {
}
interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down Expand Up @@ -5363,7 +5363,7 @@ declare module "cloudflare:workers" {
protected env: Env;
constructor(ctx: DurableObjectState, env: Env);
fetch?(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
2 changes: 1 addition & 1 deletion types/generated-snapshot/2022-03-21/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ export interface Cloudflare {
}
export interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
4 changes: 2 additions & 2 deletions types/generated-snapshot/2022-08-04/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ interface Cloudflare {
}
interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down Expand Up @@ -5364,7 +5364,7 @@ declare module "cloudflare:workers" {
protected env: Env;
constructor(ctx: DurableObjectState, env: Env);
fetch?(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
2 changes: 1 addition & 1 deletion types/generated-snapshot/2022-08-04/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ export interface Cloudflare {
}
export interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
4 changes: 2 additions & 2 deletions types/generated-snapshot/2022-10-31/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -485,7 +485,7 @@ interface Cloudflare {
}
interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down Expand Up @@ -5367,7 +5367,7 @@ declare module "cloudflare:workers" {
protected env: Env;
constructor(ctx: DurableObjectState, env: Env);
fetch?(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
2 changes: 1 addition & 1 deletion types/generated-snapshot/2022-10-31/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ export interface Cloudflare {
}
export interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
4 changes: 2 additions & 2 deletions types/generated-snapshot/2022-11-30/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ interface Cloudflare {
}
interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down Expand Up @@ -5372,7 +5372,7 @@ declare module "cloudflare:workers" {
protected env: Env;
constructor(ctx: DurableObjectState, env: Env);
fetch?(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
2 changes: 1 addition & 1 deletion types/generated-snapshot/2022-11-30/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ export interface Cloudflare {
}
export interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
4 changes: 2 additions & 2 deletions types/generated-snapshot/2023-03-01/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ interface Cloudflare {
}
interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down Expand Up @@ -5374,7 +5374,7 @@ declare module "cloudflare:workers" {
protected env: Env;
constructor(ctx: DurableObjectState, env: Env);
fetch?(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
2 changes: 1 addition & 1 deletion types/generated-snapshot/2023-03-01/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ export interface Cloudflare {
}
export interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
4 changes: 2 additions & 2 deletions types/generated-snapshot/2023-07-01/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ interface Cloudflare {
}
interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down Expand Up @@ -5374,7 +5374,7 @@ declare module "cloudflare:workers" {
protected env: Env;
constructor(ctx: DurableObjectState, env: Env);
fetch?(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
2 changes: 1 addition & 1 deletion types/generated-snapshot/2023-07-01/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -495,7 +495,7 @@ export interface Cloudflare {
}
export interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
4 changes: 2 additions & 2 deletions types/generated-snapshot/experimental/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -491,7 +491,7 @@ interface Cloudflare {
}
interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down Expand Up @@ -5440,7 +5440,7 @@ declare module "cloudflare:workers" {
protected env: Env;
constructor(ctx: DurableObjectState, env: Env);
fetch?(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
2 changes: 1 addition & 1 deletion types/generated-snapshot/experimental/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -496,7 +496,7 @@ export interface Cloudflare {
}
export interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
4 changes: 2 additions & 2 deletions types/generated-snapshot/oldest/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -467,7 +467,7 @@ interface Cloudflare {
}
interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down Expand Up @@ -5312,7 +5312,7 @@ declare module "cloudflare:workers" {
protected env: Env;
constructor(ctx: DurableObjectState, env: Env);
fetch?(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
2 changes: 1 addition & 1 deletion types/generated-snapshot/oldest/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -472,7 +472,7 @@ export interface Cloudflare {
}
export interface DurableObject {
fetch(request: Request): Response | Promise<Response>;
alarm?(): void | Promise<void>;
alarm?(alarmInfo?: AlarmInvocationInfo): void | Promise<void>;
webSocketMessage?(
ws: WebSocket,
message: string | ArrayBuffer,
Expand Down
22 changes: 22 additions & 0 deletions types/test/types/rpc.ts
Original file line number Diff line number Diff line change
Expand Up @@ -306,6 +306,27 @@ class TestObject extends DurableObject {
}
}

class TestAlarmObject extends DurableObject {
// Can declare alarm method consuming optional alarmInfo parameter
async alarm(alarmInfo?: AlarmInvocationInfo) {
if (alarmInfo !== undefined) {
Copy link
Contributor Author

@jclee jclee Dec 9, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FWIW, the current version of the runtime always passes this alarmInfo parameter, but early implementations did not, and it's likely that almost all Durable Object alarm() implementations in the wild do not currently declare the parameter. I think that means that the parameter needs to be declared alarmInfo? for backwards compatibility, although it is a bit unfortunate that this requires TS DOs to do this check for undefined before using the parameter.

I'm not sure if there is a better way to declare the method in the TS rpc.d.ts file such that it allows class implementers to either consume a (non-undefined) alarmInfo parameter or to omit it entirely.

Probably not a big deal in the common case, though, since most implementers probably won't be writing an alarm() handler that needs the info in the parameter?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dumb question: is there a way to set the alarmInfo as always passed as of a particular compatibility date?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not dumb -- I was wondering myself, but am not familiar with how we are doing versioning and backwards compatibility of TypeScript declarations.

I assume the purpose of the various types/generated-snapshot/* files might be to allow for compatibility-breaking changes in types, but I'm not sure if there is a correspondence to compatibility dates. I think marking the parameter as mandatory would not be backwards compatible, in the sense that it could cause TS to issue new errors or warnings for existing worker code -- either for alarm() handler definitions, or in cases where worker code tries to invoke alarm() handlers directly.

I suspect this feature will be infrequently used enough that it might not be worth breaking backwards compatibility for, by itself -- but if there comes a time when we're breaking backwards compatibility anyway, that might be a convenient time to make the parameter mandatory?

const _isRetry: boolean = alarmInfo.isRetry;
const _retryCount: number = alarmInfo.retryCount;
}
}

// User code can invoke alarm() directly, if desired.
async runAlarmVoid(): Promise<void> {
return await this.alarm();
}
async runAlarmInfo(): Promise<void> {
return await this.alarm({
isRetry: true,
retryCount: 1,
});
}
}

class TestNaughtyEntrypoint extends WorkerEntrypoint {
// Check incorrectly typed methods
// @ts-expect-error
Expand Down Expand Up @@ -351,6 +372,7 @@ interface Env {

REGULAR_OBJECT: DurableObjectNamespace;
RPC_OBJECT: DurableObjectNamespace<TestObject>;
ALARM_OBJECT: DurableObjectNamespace<TestAlarmObject>;
NAUGHTY_OBJECT: DurableObjectNamespace<TestNaughtyObject>;
// @ts-expect-error `BoringClass` isn't an RPC capable type
__INVALID_OBJECT_1: DurableObjectNamespace<BoringClass>;
Expand Down
Loading