diff --git a/apps/browser/src/platform/services/browser-task-scheduler.service.spec.ts b/apps/browser/src/platform/services/browser-task-scheduler.service.spec.ts index 8a080ba14a..45a16474e5 100644 --- a/apps/browser/src/platform/services/browser-task-scheduler.service.spec.ts +++ b/apps/browser/src/platform/services/browser-task-scheduler.service.spec.ts @@ -80,23 +80,6 @@ describe("BrowserTaskSchedulerService", () => { }); describe("setTimeout", () => { - it("uses the global setTimeout API if the delay is less than 1000ms", async () => { - const delayInMs = 999; - jest.spyOn(globalThis, "setTimeout"); - - await browserTaskSchedulerService.setTimeout( - ScheduledTaskNames.loginStrategySessionTimeout, - delayInMs, - ); - - expect(globalThis.setTimeout).toHaveBeenCalledWith(expect.any(Function), delayInMs); - expect(chrome.alarms.create).not.toHaveBeenCalledWith( - ScheduledTaskNames.loginStrategySessionTimeout, - { delayInMinutes: 1 }, - expect.any(Function), - ); - }); - it("creates a timeout alarm", async () => { await browserTaskSchedulerService.setTimeout( ScheduledTaskNames.loginStrategySessionTimeout, @@ -142,5 +125,22 @@ describe("BrowserTaskSchedulerService", () => { expect.any(Function), ); }); + + it("uses the global setTimeout API if the delay is less than 1000ms", async () => { + const delayInMs = 15000; + jest.spyOn(globalThis, "setTimeout"); + + await browserTaskSchedulerService.setTimeout( + ScheduledTaskNames.loginStrategySessionTimeout, + delayInMs, + ); + + expect(globalThis.setTimeout).toHaveBeenCalledWith(expect.any(Function), delayInMs); + expect(chrome.alarms.create).toHaveBeenCalledWith( + `${userUuid}__${ScheduledTaskNames.loginStrategySessionTimeout}`, + { delayInMinutes: 0.5 }, + expect.any(Function), + ); + }); }); }); diff --git a/apps/browser/src/platform/services/browser-task-scheduler.service.ts b/apps/browser/src/platform/services/browser-task-scheduler.service.ts index 34e424dc63..1105e70e33 100644 --- a/apps/browser/src/platform/services/browser-task-scheduler.service.ts +++ b/apps/browser/src/platform/services/browser-task-scheduler.service.ts @@ -52,15 +52,22 @@ export class BrowserTaskSchedulerServiceImplementation taskName: ScheduledTaskName, delayInMs: number, ): Promise { - const delayInMinutes = delayInMs / 1000 / 60; - if (delayInMinutes < 1) { - return super.setTimeout(taskName, delayInMs); - } - this.validateRegisteredTask(taskName); + const delayInMinutes = delayInMs / 1000 / 60; const alarmName = await this.getActiveUserAlarmName(taskName); - await this.scheduleAlarm(alarmName, { delayInMinutes }); + await this.scheduleAlarm(alarmName, { + delayInMinutes: this.getUpperBoundDelayInMinutes(delayInMinutes), + }); + + // If the delay is less than a minute, we want to attempt to trigger the task through a setTimeout. + // The alarm previously scheduled will be used as a backup in case the setTimeout fails. + if (delayInMinutes < 1) { + return globalThis.setTimeout(async () => { + await this.triggerTask(alarmName); + await this.clearScheduledAlarm(alarmName); + }, delayInMs); + } } /** @@ -396,4 +403,16 @@ export class BrowserTaskSchedulerServiceImplementation private isNonChromeEnvironment(): boolean { return typeof browser !== "undefined" && !!browser.alarms; } + + /** + * Gets the upper bound delay in minutes for a given delay in minutes. This is + * used to ensure that the delay is at least 1 minute in non-Chrome environments. + * In Chrome environments, the delay can be as low as 0.5 minutes. + * + * @param delayInMinutes - The delay in minutes. + */ + private getUpperBoundDelayInMinutes(delayInMinutes: number): number { + const minDelayInMinutes = this.isNonChromeEnvironment() ? 1 : 0.5; + return Math.max(minDelayInMinutes, delayInMinutes); + } }