1
0
mirror of https://github.com/bitwarden/browser.git synced 2024-09-13 01:58:44 +02:00

[PM-6426] Implementing methodology for having a fallback to setTimeout if the browser context is lost in some manner

This commit is contained in:
Cesar Gonzalez 2024-05-01 12:12:32 -05:00
parent 9cf7e0590a
commit e82a52961b
No known key found for this signature in database
GPG Key ID: 3381A5457F8CCECF
2 changed files with 42 additions and 23 deletions

View File

@ -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),
);
});
});
});

View File

@ -52,15 +52,22 @@ export class BrowserTaskSchedulerServiceImplementation
taskName: ScheduledTaskName,
delayInMs: number,
): Promise<number | NodeJS.Timeout> {
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);
}
}