diff --git a/apps/content/docs/helpers/publisher.md b/apps/content/docs/helpers/publisher.md index 32acb65ee..7120a10ae 100644 --- a/apps/content/docs/helpers/publisher.md +++ b/apps/content/docs/helpers/publisher.md @@ -235,6 +235,7 @@ export class PublisherDO extends PublisherDurableObject { super(ctx, env, { resume: { retentionSeconds: 60 * 2, // Retain events for 2 minutes to support resume + cleanupIntervalSeconds: 12 * 60 * 60, // Interval for inactivity checks; if inactive, the DO is cleaned up (default: 12 hours) }, }) } diff --git a/packages/publisher-durable-object/src/resume-storage.test.ts b/packages/publisher-durable-object/src/resume-storage.test.ts index 463ee8553..d48455269 100644 --- a/packages/publisher-durable-object/src/resume-storage.test.ts +++ b/packages/publisher-durable-object/src/resume-storage.test.ts @@ -293,22 +293,22 @@ describe('resumeStorage', () => { expect(ctx.storage.setAlarm).toHaveBeenCalledOnce() }) - it('uses custom inactiveDataRetentionTime for alarm scheduling', async () => { + it('uses custom cleanupIntervalSeconds for alarm scheduling', async () => { const ctx = createDurableObjectState() const storage = new ResumeStorage(ctx, { retentionSeconds: 60, - inactiveDataRetentionTime: 120, + cleanupIntervalSeconds: 120, }) await storage.store(JSON.stringify({ data: 'test' })) - // Alarm should be scheduled at retentionSeconds + inactiveDataRetentionTime + // Alarm should be scheduled at cleanupIntervalSeconds expect(ctx.storage.setAlarm).toHaveBeenCalledWith( expect.any(Number), ) const alarmTime = ctx.storage.setAlarm.mock.calls[0]![0] - const expectedDelay = (60 + 120) * 1000 + const expectedDelay = 120 * 1000 expect(alarmTime).toBeGreaterThanOrEqual(Date.now() + expectedDelay - 1000) expect(alarmTime).toBeLessThanOrEqual(Date.now() + expectedDelay + 1000) }) diff --git a/packages/publisher-durable-object/src/resume-storage.ts b/packages/publisher-durable-object/src/resume-storage.ts index f3f1f15c2..9e8f6c443 100644 --- a/packages/publisher-durable-object/src/resume-storage.ts +++ b/packages/publisher-durable-object/src/resume-storage.ts @@ -18,14 +18,15 @@ export interface ResumeStorageOptions { retentionSeconds?: number /** - * How long (in seconds) of inactivity before auto-deleting the durable object's data. - * Inactivity means no active WebSocket connections and no events within the retention period. + * Interval (in seconds) between cleanup checks for the Durable Object. * - * The alarm is scheduled at `retentionSeconds + inactiveDataRetentionTime`. + * At each interval, verify whether the Durable Object is inactive + * (no active WebSocket connections and no stored events). If inactive, all + * data is deleted to free resources; otherwise, another check is scheduled. * - * @default 6 * 60 * 60 (6 hours) + * @default 12 * 60 * 60 (12 hours) */ - inactiveDataRetentionTime?: number + cleanupIntervalSeconds?: number /** * Prefix for the resume storage table schema. @@ -38,7 +39,7 @@ export interface ResumeStorageOptions { export class ResumeStorage { private readonly retentionSeconds: number - private readonly inactiveDataRetentionTime: number + private readonly cleanupIntervalSeconds: number private readonly schemaPrefix: string private isInitedSchema = false @@ -54,7 +55,7 @@ export class ResumeStorage { options: ResumeStorageOptions = {}, ) { this.retentionSeconds = options.retentionSeconds ?? 0 - this.inactiveDataRetentionTime = options.inactiveDataRetentionTime ?? 6 * 60 * 60 + this.cleanupIntervalSeconds = options.cleanupIntervalSeconds ?? 12 * 60 * 60 this.schemaPrefix = options.schemaPrefix ?? 'orpc:publisher:resume:' } @@ -230,6 +231,6 @@ export class ResumeStorage { } private scheduleAlarm(): Promise { - return this.ctx.storage.setAlarm(Date.now() + (this.retentionSeconds + this.inactiveDataRetentionTime) * 1000) + return this.ctx.storage.setAlarm(Date.now() + this.cleanupIntervalSeconds * 1000) } }