@powersync/web 1.28.2 → 1.29.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.umd.js +71 -9
- package/dist/index.umd.js.map +1 -1
- package/dist/worker/SharedSyncImplementation.umd.js +12400 -8435
- package/dist/worker/SharedSyncImplementation.umd.js.map +1 -1
- package/dist/worker/WASQLiteDB.umd.js +12888 -10926
- package/dist/worker/WASQLiteDB.umd.js.map +1 -1
- package/lib/package.json +2 -2
- package/lib/src/db/adapters/AsyncDatabaseConnection.d.ts +15 -0
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.d.ts +2 -1
- package/lib/src/db/adapters/LockedAsyncDatabaseAdapter.js +17 -2
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.d.ts +3 -0
- package/lib/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.js +11 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.d.ts +22 -0
- package/lib/src/db/adapters/wa-sqlite/WASQLiteConnection.js +32 -0
- package/lib/src/worker/db/SharedWASQLiteConnection.d.ts +42 -0
- package/lib/src/worker/db/SharedWASQLiteConnection.js +90 -0
- package/lib/src/worker/db/WASQLiteDB.worker.js +22 -39
- package/lib/src/worker/db/WorkerWASQLiteConnection.d.ts +9 -0
- package/lib/src/worker/db/WorkerWASQLiteConnection.js +12 -0
- package/lib/src/worker/sync/SharedSyncImplementation.d.ts +2 -2
- package/lib/src/worker/sync/SharedSyncImplementation.js +7 -4
- package/lib/tsconfig.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/src/db/adapters/AsyncDatabaseConnection.ts +15 -0
- package/src/db/adapters/LockedAsyncDatabaseAdapter.ts +29 -10
- package/src/db/adapters/WorkerWrappedAsyncDatabaseConnection.ts +14 -0
- package/src/db/adapters/wa-sqlite/WASQLiteConnection.ts +45 -0
- package/src/worker/db/SharedWASQLiteConnection.ts +131 -0
- package/src/worker/db/WASQLiteDB.worker.ts +25 -54
- package/src/worker/db/WorkerWASQLiteConnection.ts +14 -0
- package/src/worker/sync/SharedSyncImplementation.ts +15 -12
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3460.index.umd.js +0 -355
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3460.index.umd.js.map +0 -1
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3461.index.umd.js +0 -355
- package/dist/_journeyapps_wa-sqlite-_journeyapps_wa-sqlite_src_examples_AccessHandlePoolVFS_js-_journeyapp-81d3461.index.umd.js.map +0 -1
|
@@ -60,12 +60,26 @@ export class WorkerWrappedAsyncDatabaseConnection<Config extends ResolvedWebSQLO
|
|
|
60
60
|
this.notifyRemoteClosed!.abort();
|
|
61
61
|
}
|
|
62
62
|
|
|
63
|
+
markHold(): Promise<string> {
|
|
64
|
+
return this.withRemote(() => this.baseConnection.markHold());
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
releaseHold(holdId: string): Promise<void> {
|
|
68
|
+
return this.withRemote(() => this.baseConnection.releaseHold(holdId));
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
isAutoCommit(): Promise<boolean> {
|
|
72
|
+
return this.withRemote(() => this.baseConnection.isAutoCommit());
|
|
73
|
+
}
|
|
74
|
+
|
|
63
75
|
private withRemote<T>(workerPromise: () => Promise<T>): Promise<T> {
|
|
64
76
|
const controller = this.notifyRemoteClosed;
|
|
65
77
|
if (controller) {
|
|
66
78
|
return new Promise((resolve, reject) => {
|
|
67
79
|
if (controller.signal.aborted) {
|
|
68
80
|
reject(new Error('Called operation on closed remote'));
|
|
81
|
+
// Don't run the operation if we're going to reject
|
|
82
|
+
return;
|
|
69
83
|
}
|
|
70
84
|
|
|
71
85
|
function handleAbort() {
|
|
@@ -26,6 +26,14 @@ export type WASQLiteBroadCastTableUpdateEvent = {
|
|
|
26
26
|
*/
|
|
27
27
|
export type WASQLiteConnectionListener = {
|
|
28
28
|
tablesUpdated: (event: BatchedUpdateNotification) => void;
|
|
29
|
+
/**
|
|
30
|
+
* Triggered when an active hold is overwritten by a new hold.
|
|
31
|
+
* This is most likely to happen when a shared connection has been closed
|
|
32
|
+
* without releasing the hold.
|
|
33
|
+
* This listener can be used to cleanup any resources associated with the previous hold.
|
|
34
|
+
* @param holdId - The id of the hold that has been overwritten.
|
|
35
|
+
*/
|
|
36
|
+
holdOverwritten: (holdId: string) => Promise<void>;
|
|
29
37
|
};
|
|
30
38
|
|
|
31
39
|
/**
|
|
@@ -148,6 +156,9 @@ export class WASqliteConnection
|
|
|
148
156
|
*/
|
|
149
157
|
protected connectionId: number;
|
|
150
158
|
|
|
159
|
+
protected _holdCounter: number;
|
|
160
|
+
protected _holdId: string | null;
|
|
161
|
+
|
|
151
162
|
constructor(protected options: ResolvedWASQLiteOpenFactoryOptions) {
|
|
152
163
|
super();
|
|
153
164
|
this.updatedTables = new Set();
|
|
@@ -156,6 +167,16 @@ export class WASqliteConnection
|
|
|
156
167
|
this.connectionId = new Date().valueOf() + Math.random();
|
|
157
168
|
this.statementMutex = new Mutex();
|
|
158
169
|
this._moduleFactory = DEFAULT_MODULE_FACTORIES[this.options.vfs];
|
|
170
|
+
this._holdCounter = 0;
|
|
171
|
+
this._holdId = null;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Gets the id for the current hold.
|
|
176
|
+
* This can be used to check for invalid states.
|
|
177
|
+
*/
|
|
178
|
+
get currentHoldId() {
|
|
179
|
+
return this._holdId;
|
|
159
180
|
}
|
|
160
181
|
|
|
161
182
|
protected get sqliteAPI() {
|
|
@@ -172,6 +193,30 @@ export class WASqliteConnection
|
|
|
172
193
|
return this._dbP;
|
|
173
194
|
}
|
|
174
195
|
|
|
196
|
+
/**
|
|
197
|
+
* Checks if the database connection is in autocommit mode.
|
|
198
|
+
* @returns true if in autocommit mode, false if in a transaction
|
|
199
|
+
*/
|
|
200
|
+
async isAutoCommit(): Promise<boolean> {
|
|
201
|
+
return this.sqliteAPI.get_autocommit(this.dbP) != 0;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
async markHold(): Promise<string> {
|
|
205
|
+
const previousHoldId = this._holdId;
|
|
206
|
+
this._holdId = `${++this._holdCounter}`;
|
|
207
|
+
if (previousHoldId) {
|
|
208
|
+
await this.iterateAsyncListeners(async (cb) => cb.holdOverwritten?.(previousHoldId));
|
|
209
|
+
}
|
|
210
|
+
return this._holdId;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
async releaseHold(holdId: string): Promise<void> {
|
|
214
|
+
if (holdId != this._holdId) {
|
|
215
|
+
throw new Error(`Invalid hold state, expected ${this._holdId} but got ${holdId}`);
|
|
216
|
+
}
|
|
217
|
+
this._holdId = null;
|
|
218
|
+
}
|
|
219
|
+
|
|
175
220
|
protected async openDB() {
|
|
176
221
|
this._dbP = await this.sqliteAPI.open_v2(this.options.dbFilename);
|
|
177
222
|
return this._dbP;
|
|
@@ -0,0 +1,131 @@
|
|
|
1
|
+
import { ILogger } from '@powersync/common';
|
|
2
|
+
import {
|
|
3
|
+
AsyncDatabaseConnection,
|
|
4
|
+
OnTableChangeCallback,
|
|
5
|
+
ProxiedQueryResult
|
|
6
|
+
} from '../../db/adapters/AsyncDatabaseConnection';
|
|
7
|
+
import { ResolvedWebSQLOpenOptions } from '../../db/adapters/web-sql-flags';
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* Keeps track of open DB connections and the clients which
|
|
11
|
+
* are using it.
|
|
12
|
+
*/
|
|
13
|
+
export type SharedDBWorkerConnection = {
|
|
14
|
+
clientIds: Set<number>;
|
|
15
|
+
db: AsyncDatabaseConnection;
|
|
16
|
+
};
|
|
17
|
+
|
|
18
|
+
export type SharedWASQLiteConnectionOptions = {
|
|
19
|
+
dbMap: Map<string, SharedDBWorkerConnection>;
|
|
20
|
+
dbFilename: string;
|
|
21
|
+
clientId: number;
|
|
22
|
+
logger: ILogger;
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
export class SharedWASQLiteConnection implements AsyncDatabaseConnection {
|
|
26
|
+
protected isClosing: boolean;
|
|
27
|
+
// Keeps track if this current hold if the shared connection has a hold
|
|
28
|
+
protected activeHoldId: string | null;
|
|
29
|
+
|
|
30
|
+
constructor(protected options: SharedWASQLiteConnectionOptions) {
|
|
31
|
+
// Add this client ID to the set of known clients
|
|
32
|
+
this.clientIds.add(options.clientId);
|
|
33
|
+
this.isClosing = false;
|
|
34
|
+
this.activeHoldId = null;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
protected get logger() {
|
|
38
|
+
return this.options.logger;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
protected get dbEntry() {
|
|
42
|
+
return this.options.dbMap.get(this.options.dbFilename)!;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
protected get connection() {
|
|
46
|
+
return this.dbEntry.db;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
protected get clientIds() {
|
|
50
|
+
return this.dbEntry.clientIds;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
async init(): Promise<void> {
|
|
54
|
+
// No-op since the connection is already initialized when it was created
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
async markHold(): Promise<string> {
|
|
58
|
+
this.activeHoldId = await this.connection.markHold();
|
|
59
|
+
return this.activeHoldId;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
async releaseHold(id: string): Promise<void> {
|
|
63
|
+
try {
|
|
64
|
+
await this.connection.releaseHold(id);
|
|
65
|
+
} finally {
|
|
66
|
+
this.activeHoldId = null;
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
async isAutoCommit(): Promise<boolean> {
|
|
71
|
+
return this.connection.isAutoCommit();
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Handles closing of a shared connection.
|
|
76
|
+
* The connection is only closed if there are no active clients using it.
|
|
77
|
+
*/
|
|
78
|
+
async close(): Promise<void> {
|
|
79
|
+
// This prevents further statements on this connection from being executed
|
|
80
|
+
this.isClosing = true;
|
|
81
|
+
const { clientIds, logger } = this;
|
|
82
|
+
const { clientId, dbFilename, dbMap } = this.options;
|
|
83
|
+
logger.debug(`Close requested from client ${clientId} of ${[...clientIds]}`);
|
|
84
|
+
clientIds.delete(clientId);
|
|
85
|
+
|
|
86
|
+
if (this.activeHoldId) {
|
|
87
|
+
// We can't cleanup here since we're not in a lock context.
|
|
88
|
+
// The cleanup will occur once a new hold is acquired.
|
|
89
|
+
this.logger.info(
|
|
90
|
+
`Hold ${this.activeHoldId} was still active when the connection was closed. Cleanup will occur once a new hold is acquired.`
|
|
91
|
+
);
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
if (clientIds.size == 0) {
|
|
95
|
+
logger.debug(`Closing connection to ${this.options}.`);
|
|
96
|
+
const connection = this.connection;
|
|
97
|
+
dbMap.delete(dbFilename);
|
|
98
|
+
await connection.close();
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
logger.debug(`Connection to ${dbFilename} not closed yet due to active clients.`);
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
protected async withClosing<T>(action: () => Promise<T>) {
|
|
106
|
+
if (this.isClosing) {
|
|
107
|
+
throw new Error('Connection is closing');
|
|
108
|
+
}
|
|
109
|
+
return action();
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
async execute(sql: string, params?: any[]): Promise<ProxiedQueryResult> {
|
|
113
|
+
return this.withClosing(() => this.connection.execute(sql, params));
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
async executeRaw(sql: string, params?: any[]): Promise<any[][]> {
|
|
117
|
+
return this.withClosing(() => this.connection.executeRaw(sql, params));
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
executeBatch(sql: string, params?: any[] | undefined): Promise<ProxiedQueryResult> {
|
|
121
|
+
return this.withClosing(() => this.connection.executeBatch(sql, params));
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
registerOnTableChange(callback: OnTableChangeCallback): Promise<() => void> {
|
|
125
|
+
return this.connection.registerOnTableChange(callback);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
getConfig(): Promise<ResolvedWebSQLOpenOptions> {
|
|
129
|
+
return this.connection.getConfig();
|
|
130
|
+
}
|
|
131
|
+
}
|
|
@@ -6,47 +6,20 @@ import '@journeyapps/wa-sqlite';
|
|
|
6
6
|
import { createBaseLogger, createLogger } from '@powersync/common';
|
|
7
7
|
import * as Comlink from 'comlink';
|
|
8
8
|
import { AsyncDatabaseConnection } from '../../db/adapters/AsyncDatabaseConnection';
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
ResolvedWASQLiteOpenFactoryOptions,
|
|
12
|
-
WorkerDBOpenerOptions
|
|
13
|
-
} from '../../db/adapters/wa-sqlite/WASQLiteOpenFactory';
|
|
9
|
+
import { WorkerDBOpenerOptions } from '../../db/adapters/wa-sqlite/WASQLiteOpenFactory';
|
|
14
10
|
import { getNavigatorLocks } from '../../shared/navigator';
|
|
11
|
+
import { SharedDBWorkerConnection, SharedWASQLiteConnection } from './SharedWASQLiteConnection';
|
|
12
|
+
import { WorkerWASQLiteConnection } from './WorkerWASQLiteConnection';
|
|
15
13
|
|
|
16
14
|
const baseLogger = createBaseLogger();
|
|
17
15
|
baseLogger.useDefaults();
|
|
18
16
|
const logger = createLogger('db-worker');
|
|
19
17
|
|
|
20
|
-
/**
|
|
21
|
-
* Keeps track of open DB connections and the clients which
|
|
22
|
-
* are using it.
|
|
23
|
-
*/
|
|
24
|
-
type SharedDBWorkerConnection = {
|
|
25
|
-
clientIds: Set<number>;
|
|
26
|
-
db: AsyncDatabaseConnection;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
18
|
const DBMap = new Map<string, SharedDBWorkerConnection>();
|
|
30
19
|
const OPEN_DB_LOCK = 'open-wasqlite-db';
|
|
31
20
|
|
|
32
21
|
let nextClientId = 1;
|
|
33
22
|
|
|
34
|
-
const openWorkerConnection = async (options: ResolvedWASQLiteOpenFactoryOptions): Promise<AsyncDatabaseConnection> => {
|
|
35
|
-
const connection = new WASqliteConnection(options);
|
|
36
|
-
return {
|
|
37
|
-
init: Comlink.proxy(() => connection.init()),
|
|
38
|
-
getConfig: Comlink.proxy(() => connection.getConfig()),
|
|
39
|
-
close: Comlink.proxy(() => connection.close()),
|
|
40
|
-
execute: Comlink.proxy(async (sql: string, params?: any[]) => connection.execute(sql, params)),
|
|
41
|
-
executeRaw: Comlink.proxy(async (sql: string, params?: any[]) => connection.executeRaw(sql, params)),
|
|
42
|
-
executeBatch: Comlink.proxy(async (sql: string, params?: any[]) => connection.executeBatch(sql, params)),
|
|
43
|
-
registerOnTableChange: Comlink.proxy(async (callback) => {
|
|
44
|
-
// Proxy the callback remove function
|
|
45
|
-
return Comlink.proxy(await connection.registerOnTableChange(callback));
|
|
46
|
-
})
|
|
47
|
-
};
|
|
48
|
-
};
|
|
49
|
-
|
|
50
23
|
const openDBShared = async (options: WorkerDBOpenerOptions): Promise<AsyncDatabaseConnection> => {
|
|
51
24
|
// Prevent multiple simultaneous opens from causing race conditions
|
|
52
25
|
return getNavigatorLocks().request(OPEN_DB_LOCK, async () => {
|
|
@@ -57,38 +30,36 @@ const openDBShared = async (options: WorkerDBOpenerOptions): Promise<AsyncDataba
|
|
|
57
30
|
|
|
58
31
|
if (!DBMap.has(dbFilename)) {
|
|
59
32
|
const clientIds = new Set<number>();
|
|
60
|
-
|
|
33
|
+
// This format returns proxy objects for function callbacks
|
|
34
|
+
const connection = new WorkerWASQLiteConnection(options);
|
|
61
35
|
await connection.init();
|
|
36
|
+
|
|
37
|
+
connection.registerListener({
|
|
38
|
+
holdOverwritten: async () => {
|
|
39
|
+
/**
|
|
40
|
+
* The previous hold has been overwritten, without being released.
|
|
41
|
+
* we need to cleanup any resources associated with it.
|
|
42
|
+
* We can perform a rollback to release any potential transactions that were started.
|
|
43
|
+
*/
|
|
44
|
+
await connection.execute('ROLLBACK').catch(() => {});
|
|
45
|
+
}
|
|
46
|
+
});
|
|
47
|
+
|
|
62
48
|
DBMap.set(dbFilename, {
|
|
63
49
|
clientIds,
|
|
64
50
|
db: connection
|
|
65
51
|
});
|
|
66
52
|
}
|
|
67
53
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
// the init has been done automatically
|
|
76
|
-
}),
|
|
77
|
-
close: Comlink.proxy(async () => {
|
|
78
|
-
const { clientIds } = dbEntry;
|
|
79
|
-
logger.debug(`Close requested from client ${clientId} of ${[...clientIds]}`);
|
|
80
|
-
clientIds.delete(clientId);
|
|
81
|
-
if (clientIds.size == 0) {
|
|
82
|
-
logger.debug(`Closing connection to ${dbFilename}.`);
|
|
83
|
-
DBMap.delete(dbFilename);
|
|
84
|
-
return db.close?.();
|
|
85
|
-
}
|
|
86
|
-
logger.debug(`Connection to ${dbFilename} not closed yet due to active clients.`);
|
|
87
|
-
return;
|
|
88
|
-
})
|
|
89
|
-
};
|
|
54
|
+
// Associates this clientId with the shared connection entry
|
|
55
|
+
const sharedConnection = new SharedWASQLiteConnection({
|
|
56
|
+
dbMap: DBMap,
|
|
57
|
+
dbFilename,
|
|
58
|
+
clientId,
|
|
59
|
+
logger
|
|
60
|
+
});
|
|
90
61
|
|
|
91
|
-
return Comlink.proxy(
|
|
62
|
+
return Comlink.proxy(sharedConnection);
|
|
92
63
|
});
|
|
93
64
|
};
|
|
94
65
|
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import * as Comlink from 'comlink';
|
|
2
|
+
import { OnTableChangeCallback } from '../../db/adapters/AsyncDatabaseConnection';
|
|
3
|
+
import { WASqliteConnection } from '../../db/adapters/wa-sqlite/WASQLiteConnection';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* A Small proxy wrapper around the WASqliteConnection.
|
|
7
|
+
* This ensures that certain return types are properly proxied.
|
|
8
|
+
*/
|
|
9
|
+
export class WorkerWASQLiteConnection extends WASqliteConnection {
|
|
10
|
+
async registerOnTableChange(callback: OnTableChangeCallback): Promise<() => void> {
|
|
11
|
+
// Proxy the callback remove function
|
|
12
|
+
return Comlink.proxy(await super.registerOnTableChange(callback));
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -1,10 +1,4 @@
|
|
|
1
1
|
import {
|
|
2
|
-
type ILogger,
|
|
3
|
-
type ILogLevel,
|
|
4
|
-
type PowerSyncConnectionOptions,
|
|
5
|
-
type StreamingSyncImplementation,
|
|
6
|
-
type StreamingSyncImplementationListener,
|
|
7
|
-
type SyncStatusOptions,
|
|
8
2
|
AbortOperation,
|
|
9
3
|
BaseObserver,
|
|
10
4
|
ConnectionManager,
|
|
@@ -13,7 +7,13 @@ import {
|
|
|
13
7
|
PowerSyncBackendConnector,
|
|
14
8
|
SqliteBucketStorage,
|
|
15
9
|
SubscribedStream,
|
|
16
|
-
SyncStatus
|
|
10
|
+
SyncStatus,
|
|
11
|
+
type ILogger,
|
|
12
|
+
type ILogLevel,
|
|
13
|
+
type PowerSyncConnectionOptions,
|
|
14
|
+
type StreamingSyncImplementation,
|
|
15
|
+
type StreamingSyncImplementationListener,
|
|
16
|
+
type SyncStatusOptions
|
|
17
17
|
} from '@powersync/common';
|
|
18
18
|
import { Mutex } from 'async-mutex';
|
|
19
19
|
import * as Comlink from 'comlink';
|
|
@@ -75,7 +75,7 @@ export type WrappedSyncPort = {
|
|
|
75
75
|
clientProvider: Comlink.Remote<AbstractSharedSyncClientProvider>;
|
|
76
76
|
db?: DBAdapter;
|
|
77
77
|
currentSubscriptions: SubscribedStream[];
|
|
78
|
-
closeListeners: (() => void)[];
|
|
78
|
+
closeListeners: (() => void | Promise<void>)[];
|
|
79
79
|
};
|
|
80
80
|
|
|
81
81
|
/**
|
|
@@ -334,12 +334,15 @@ export class SharedSyncImplementation extends BaseObserver<SharedSyncImplementat
|
|
|
334
334
|
}
|
|
335
335
|
|
|
336
336
|
for (const closeListener of trackedPort.closeListeners) {
|
|
337
|
-
closeListener();
|
|
337
|
+
await closeListener();
|
|
338
338
|
}
|
|
339
339
|
|
|
340
340
|
if (this.dbAdapter && this.dbAdapter == trackedPort.db) {
|
|
341
341
|
// Unconditionally close the connection because the database it's writing to has just been closed.
|
|
342
|
-
|
|
342
|
+
// The connection has been closed previously, this might throw. We should be able to ignore it.
|
|
343
|
+
await this.connectionManager
|
|
344
|
+
.disconnect()
|
|
345
|
+
.catch((ex) => this.logger.warn('Error while disconnecting. Will attempt to reconnect.', ex));
|
|
343
346
|
|
|
344
347
|
// Clearing the adapter will result in a new one being opened in connect
|
|
345
348
|
this.dbAdapter = null;
|
|
@@ -482,9 +485,9 @@ export class SharedSyncImplementation extends BaseObserver<SharedSyncImplementat
|
|
|
482
485
|
// that and ensure pending requests are aborted when the tab is closed.
|
|
483
486
|
remoteCanCloseUnexpectedly: true
|
|
484
487
|
});
|
|
485
|
-
lastClient.closeListeners.push(() => {
|
|
488
|
+
lastClient.closeListeners.push(async () => {
|
|
486
489
|
this.logger.info('Aborting open connection because associated tab closed.');
|
|
487
|
-
wrapped.close();
|
|
490
|
+
await wrapped.close().catch((ex) => this.logger.warn('error closing database connection', ex));
|
|
488
491
|
wrapped.markRemoteClosed();
|
|
489
492
|
});
|
|
490
493
|
|