Skip to content

[Proposal] Add ability to list and cancel scheduled actions #805

@zephraph

Description

@zephraph

Currently the scheduling API is fairly constrained.

We're able to schedule future work via c.schedule.after and c.schedule.at. There's not, to the best of my knowledge, a mechanism to either see what work is scheduled, nor to cancel any of the scheduled work. One may want to, for example, schedule a drip email campaign in an actor but allow the user to disable emails at a later time (which means you'd need to clear all the scheduled emails).

There are two parts to this proposal.

List Scheduled Work

Add a list method to schedule to list the actions that are currently scheduled to run.

type Events = readonly { eventId: string, timestamp: number, fn: string, args: unknown[] }
const events: Events[] = c.schedule.list()

This could be implemented with the drivers as-is and should be broadly supportable across implementations.

Cancel Scheduled Work

This is more involved. I don't know the shape of rivets infra, so I'm going to come at this from the cloudflare perspective.

Cloudflare implements three alarm APIs:

getAlarm(): number | null
setAlarm(ms: number): void
deleteAlarm(): void

Note: Durable objects only support a single alarm so that seems like the lowest common denominator

To support this feature we'll need to make the following changes to the ActorDriver interface:

interface ActorDriver {
    get context(): unknown;
    kvGet(actorId: string, key: KvKey): Promise<KvValue | undefined>;
    kvGetBatch(actorId: string, key: KvKey[]): Promise<(KvValue | undefined)[]>;
    kvPut(actorId: string, key: KvKey, value: KvValue): Promise<void>;
    kvPutBatch(actorId: string, key: [KvKey, KvValue][]): Promise<void>;
    kvDelete(actorId: string, key: KvKey): Promise<void>;
    kvDeleteBatch(actorId: string, key: KvKey[]): Promise<void>;
+   setAlarm(actor: AnyActorInstance, timestamp: number): Promise<void>;
+   getAlarm(actor: AnyActorInstance): Promise<number | null>;
+   deleteAlarm(actor: AnyActorInstance): Promise<void>
}

This suggestion more or less maps to cloudflare's API exactly, with the exception of being async instead of sync.

As for Schedule, I think we should make the following changes:

interface Schedule {
   // after and at now return their `eventId`
   after: (duration: number, fn: string, ...args: unknown[]) => Promise<string>;
   at: (timestamp: number, fn: string, ...args: unknown[]) => Promise<string>;

   get: (alarmId: string) => Promise<Alarm>;
   cancel: (alarmId: string) => Promise<void>;

   // Included from the above proposal
   list: () => Promise<Alarm[]>;
}

// Like the `ScheduleEvent` interface but public
interface Alarm {
  id: string;
  createdAt: number; // <-- This is just a nice to have but it would provide a sense of progress
  triggersAt: number;
  fn: string;
  args: unknown[];
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions