Add Retries to `get` (#11176)

This commit is contained in:
Justin Baur 2024-09-23 16:39:57 -04:00 committed by GitHub
parent 08f0dadc2f
commit 073fd29206
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 61 additions and 4 deletions

View File

@ -419,7 +419,7 @@ export default class MainBackground {
this.logService = new ConsoleLogService(isDev);
this.cryptoFunctionService = new WebCryptoFunctionService(self);
this.keyGenerationService = new KeyGenerationService(this.cryptoFunctionService);
this.storageService = new BrowserLocalStorageService();
this.storageService = new BrowserLocalStorageService(this.logService);
this.intraprocessMessagingSubject = new Subject<Message<Record<string, unknown>>>();

View File

@ -1,10 +1,67 @@
import AbstractChromeStorageService from "./abstractions/abstract-chrome-storage-api.service";
import { LogService } from "@bitwarden/common/platform/abstractions/log.service";
import AbstractChromeStorageService, {
SerializedValue,
} from "./abstractions/abstract-chrome-storage-api.service";
export default class BrowserLocalStorageService extends AbstractChromeStorageService {
constructor() {
constructor(private readonly logService: LogService) {
super(chrome.storage.local);
}
override async get<T>(key: string): Promise<T> {
return await this.getWithRetries<T>(key, 0);
}
private async getWithRetries<T>(key: string, retryNum: number): Promise<T> {
// See: https://github.com/EFForg/privacybadger/pull/2980
const MAX_RETRIES = 5;
const WAIT_TIME = 200;
const store = await this.getStore(key);
if (store == null) {
if (retryNum >= MAX_RETRIES) {
throw new Error(`Failed to get a value for key '${key}', see logs for more details.`);
}
retryNum++;
this.logService.warning(`Retrying attempt to get value for key '${key}' in ${WAIT_TIME}ms`);
await new Promise<void>((resolve) => setTimeout(resolve, WAIT_TIME));
return await this.getWithRetries(key, retryNum);
}
// We have a store
return this.processGetObject<T>(store[key] as T | SerializedValue);
}
private async getStore(key: string) {
if (this.chromeStorageApi == null) {
this.logService.warning(
`chrome.storage.local was not initialized while retrieving key '${key}'.`,
);
return null;
}
return new Promise<{ [key: string]: unknown }>((resolve) => {
this.chromeStorageApi.get(key, (store) => {
if (chrome.runtime.lastError) {
this.logService.warning(`Failed to get value for key '${key}'`, chrome.runtime.lastError);
resolve(null);
return;
}
if (store == null) {
this.logService.warning(`Store was empty while retrieving value for key '${key}'`);
resolve(null);
return;
}
resolve(store);
});
});
}
async fillBuffer() {
// Write 4MB of data in chrome.storage.local, log files will hold 4MB of data (by default)
// before forcing a compaction. To force a compaction and have it remove previously saved data,

View File

@ -304,7 +304,7 @@ const safeProviders: SafeProvider[] = [
safeProvider({
provide: AbstractStorageService,
useClass: BrowserLocalStorageService,
deps: [],
deps: [LogService],
}),
safeProvider({
provide: AutofillServiceAbstraction,