Skip to content

Commit 089fcdd

Browse files
committed
Merge branch 'master' into wuandy/Bundles
# Conflicts: # packages/firestore/exp/test/shim.ts # packages/firestore/src/api/database.ts
2 parents 5b0526b + 2d325e7 commit 089fcdd

File tree

2 files changed

+57
-13
lines changed

2 files changed

+57
-13
lines changed

packages-exp/auth-exp/src/platform_browser/persistence/indexed_db.test.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,4 +324,29 @@ describe('platform_browser/persistence/indexed_db', () => {
324324
});
325325
});
326326
});
327+
328+
describe('closed IndexedDB connection', () => {
329+
it('should retry by reopening the connection', async () => {
330+
const closeDb = async (): Promise<void> => {
331+
const db = await ((persistence as unknown) as {
332+
_openDb(): Promise<IDBDatabase>;
333+
})._openDb();
334+
db.close();
335+
};
336+
const key = 'my-super-special-persistence-type';
337+
const value = PersistenceType.LOCAL;
338+
339+
expect(await persistence._get(key)).to.be.null;
340+
341+
await closeDb();
342+
await persistence._set(key, value);
343+
344+
await closeDb();
345+
expect(await persistence._get(key)).to.be.eq(value);
346+
347+
await closeDb();
348+
await persistence._remove(key);
349+
expect(await persistence._get(key)).to.be.null;
350+
});
351+
});
327352
});

packages-exp/auth-exp/src/platform_browser/persistence/indexed_db.ts

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -164,6 +164,8 @@ function deleteObject(db: IDBDatabase, key: string): Promise<void> {
164164

165165
/** @internal */
166166
export const _POLLING_INTERVAL_MS = 800;
167+
/** @internal */
168+
export const _TRANSACTION_RETRY_COUNT = 3;
167169

168170
class IndexedDBLocalPersistence implements Persistence {
169171
static type: 'LOCAL' = 'LOCAL';
@@ -193,14 +195,34 @@ class IndexedDBLocalPersistence implements Persistence {
193195
);
194196
}
195197

196-
private async initialize(): Promise<IDBDatabase> {
198+
async _openDb(): Promise<IDBDatabase> {
197199
if (this.db) {
198200
return this.db;
199201
}
200202
this.db = await _openDatabase();
201203
return this.db;
202204
}
203205

206+
async _withRetries<T>(op: (db: IDBDatabase) => Promise<T>): Promise<T> {
207+
let numAttempts = 0;
208+
209+
while (true) {
210+
try {
211+
const db = await this._openDb();
212+
return await op(db);
213+
} catch (e) {
214+
if (numAttempts++ > _TRANSACTION_RETRY_COUNT) {
215+
throw e;
216+
}
217+
if (this.db) {
218+
this.db.close();
219+
this.db = undefined;
220+
}
221+
// TODO: consider adding exponential backoff
222+
}
223+
}
224+
}
225+
204226
/**
205227
* IndexedDB events do not propagate from the main window to the worker context. We rely on a
206228
* postMessage interface to send these events to the worker ourselves.
@@ -318,38 +340,35 @@ class IndexedDBLocalPersistence implements Persistence {
318340
}
319341

320342
async _set(key: string, value: PersistenceValue): Promise<void> {
321-
const db = await this.initialize();
322343
return this._withPendingWrite(async () => {
323-
await _putObject(db, key, value);
344+
await this._withRetries((db: IDBDatabase) => _putObject(db, key, value));
324345
this.localCache[key] = value;
325346
return this.notifyServiceWorker(key);
326347
});
327348
}
328349

329350
async _get<T extends PersistenceValue>(key: string): Promise<T | null> {
330-
const db = await this.initialize();
331-
const obj = (await getObject(db, key)) as T;
351+
const obj = (await this._withRetries((db: IDBDatabase) =>
352+
getObject(db, key)
353+
)) as T;
332354
this.localCache[key] = obj;
333355
return obj;
334356
}
335357

336358
async _remove(key: string): Promise<void> {
337-
const db = await this.initialize();
338359
return this._withPendingWrite(async () => {
339-
await deleteObject(db, key);
360+
await this._withRetries((db: IDBDatabase) => deleteObject(db, key));
340361
delete this.localCache[key];
341362
return this.notifyServiceWorker(key);
342363
});
343364
}
344365

345366
private async _poll(): Promise<string[]> {
346-
const db = await _openDatabase();
347-
348367
// TODO: check if we need to fallback if getAll is not supported
349-
const getAllRequest = getObjectStore(db, false).getAll();
350-
const result = await new DBPromise<DBObject[] | null>(
351-
getAllRequest
352-
).toPromise();
368+
const result = await this._withRetries((db: IDBDatabase) => {
369+
const getAllRequest = getObjectStore(db, false).getAll();
370+
return new DBPromise<DBObject[] | null>(getAllRequest).toPromise();
371+
});
353372

354373
if (!result) {
355374
return [];

0 commit comments

Comments
 (0)