Skip to content

Commit eb88fde

Browse files
cleanup any opened access handles if an error is caught.
1 parent 4a12be8 commit eb88fde

File tree

2 files changed

+27
-3
lines changed

2 files changed

+27
-3
lines changed

packages/web/src/db/adapters/LockedAsyncDatabaseAdapter.ts

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import {
1010
createLogger,
1111
type ILogger
1212
} from '@powersync/common';
13-
import { getNavigatorLocks } from '../..//shared/navigator';
13+
import { getNavigatorLocks } from '../../shared/navigator';
1414
import { AsyncDatabaseConnection, ConnectionClosedError } from './AsyncDatabaseConnection';
1515
import { SharedConnectionWorker, WebDBAdapter } from './WebDBAdapter';
1616
import { WorkerWrappedAsyncDatabaseConnection } from './WorkerWrappedAsyncDatabaseConnection';
@@ -120,8 +120,9 @@ export class LockedAsyncDatabaseAdapter
120120
// Dispose any previous table change listener.
121121
this._disposeTableChangeListener?.();
122122
this._disposeTableChangeListener = null;
123-
123+
this._db?.close().catch((ex) => this.logger.warn(`Error closing database before opening new instance`, ex));
124124
const isReOpen = !!this._db;
125+
this._db = null;
125126

126127
this._db = await this.options.openConnection();
127128
await this._db.init();
@@ -159,7 +160,23 @@ export class LockedAsyncDatabaseAdapter
159160
}
160161

161162
protected async _init() {
162-
await this.openInternalDB();
163+
/**
164+
* For OPFS, we can see this open call sometimes fail due to NoModificationAllowedError.
165+
* We should be able to recover from this by re-opening the database.
166+
*/
167+
const maxAttempts = 3;
168+
for (let count = 0; count < maxAttempts; count++) {
169+
try {
170+
await this.openInternalDB();
171+
break;
172+
} catch (ex) {
173+
if (count == maxAttempts - 1) {
174+
throw ex;
175+
}
176+
this.logger.warn(`Attempt ${count + 1} of ${maxAttempts} to open database failed, retrying in 1 second...`, ex);
177+
await new Promise((resolve) => setTimeout(resolve, 1000));
178+
}
179+
}
163180
this.iterateListeners((cb) => cb.initialized?.());
164181
}
165182

packages/web/src/worker/db/opfs.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -549,6 +549,13 @@ export class OPFSCoopSyncVFS extends FacadeVFS {
549549
);
550550
} catch (e) {
551551
this.log?.(`failed to create access handles for ${file.path}`, e);
552+
// Close any of the potentially opened access handles
553+
DB_RELATED_FILE_SUFFIXES.forEach(async (suffix) => {
554+
const persistentFile = this.persistentFiles.get(file.path + suffix);
555+
if (persistentFile) {
556+
persistentFile.accessHandle?.close();
557+
}
558+
});
552559
// Release the lock, if we failed here, we'd need to obtain the lock later in order to retry
553560
file.persistentFile.handleLockReleaser();
554561
throw e;

0 commit comments

Comments
 (0)