Skip to content

Commit 1ab9b38

Browse files
committed
Fix handling worker errors
1 parent 67e5e44 commit 1ab9b38

File tree

5 files changed

+89
-54
lines changed

5 files changed

+89
-54
lines changed

sqlite3_web/CHANGELOG.md

+4
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,7 @@
1+
## 0.2.2
2+
3+
- Recover from worker errors at startup.
4+
15
## 0.2.1
26

37
- Add `WebSqlite.deleteDatabase` to delete databases.

sqlite3_web/lib/src/channel.dart

+10-2
Original file line numberDiff line numberDiff line change
@@ -103,7 +103,9 @@ abstract class ProtocolChannel {
103103
final Map<int, Completer<Response>> _responses = {};
104104

105105
ProtocolChannel(this._channel) {
106-
_channel.stream.listen(_handleIncoming);
106+
_channel.stream.listen(_handleIncoming, onError: (e) {
107+
close(e);
108+
});
107109
}
108110

109111
Future<void> get closed => _channel.sink.done;
@@ -165,8 +167,14 @@ abstract class ProtocolChannel {
165167

166168
void handleNotification(Notification notification);
167169

168-
Future<void> close() async {
170+
Future<void> close([Object? error]) async {
169171
await _channel.sink.close();
172+
173+
for (final response in _responses.values) {
174+
response.completeError(
175+
StateError('Channel closed before receiving response: $error'));
176+
}
177+
_responses.clear();
170178
}
171179
}
172180

sqlite3_web/lib/src/client.dart

+44-36
Original file line numberDiff line numberDiff line change
@@ -255,16 +255,10 @@ final class DatabaseClient implements WebSqlite {
255255

256256
Future<void> _startDedicated() async {
257257
if (globalContext.has('Worker')) {
258-
final Worker dedicated;
259-
try {
260-
dedicated = Worker(
261-
workerUri.toString().toJS,
262-
WorkerOptions(name: 'sqlite3_worker'),
263-
);
264-
} on Object {
265-
_missingFeatures.add(MissingBrowserFeature.dedicatedWorkers);
266-
return;
267-
}
258+
final dedicated = Worker(
259+
workerUri.toString().toJS,
260+
WorkerOptions(name: 'sqlite3_worker'),
261+
);
268262

269263
final (endpoint, channel) = await createChannel();
270264
ConnectRequest(endpoint: endpoint, requestId: 0).sendToWorker(dedicated);
@@ -278,14 +272,8 @@ final class DatabaseClient implements WebSqlite {
278272

279273
Future<void> _startShared() async {
280274
if (globalContext.has('SharedWorker')) {
281-
final SharedWorker shared;
282-
try {
283-
shared = SharedWorker(workerUri.toString().toJS);
284-
shared.port.start();
285-
} on Object {
286-
_missingFeatures.add(MissingBrowserFeature.sharedWorkers);
287-
return;
288-
}
275+
final shared = SharedWorker(workerUri.toString().toJS);
276+
shared.port.start();
289277

290278
final (endpoint, channel) = await createChannel();
291279
ConnectRequest(endpoint: endpoint, requestId: 0).sendToPort(shared.port);
@@ -348,15 +336,22 @@ final class DatabaseClient implements WebSqlite {
348336
final available = <(StorageMode, AccessMode)>[];
349337
var workersReportedIndexedDbSupport = false;
350338

351-
if (_connectionToDedicated case final connection?) {
352-
final response = await connection.sendRequest(
353-
CompatibilityCheck(
354-
requestId: 0,
355-
type: MessageType.dedicatedCompatibilityCheck,
356-
databaseName: databaseName,
357-
),
358-
MessageType.simpleSuccessResponse,
359-
);
339+
Future<void> dedicatedCompatibilityCheck(
340+
WorkerConnection connection) async {
341+
SimpleSuccessResponse response;
342+
try {
343+
response = await connection.sendRequest(
344+
CompatibilityCheck(
345+
requestId: 0,
346+
type: MessageType.dedicatedCompatibilityCheck,
347+
databaseName: databaseName,
348+
),
349+
MessageType.simpleSuccessResponse,
350+
);
351+
} on Object {
352+
return;
353+
}
354+
360355
final result = CompatibilityResult.fromJS(response.response as JSObject);
361356
existing.addAll(result.existingDatabases);
362357
available.add((StorageMode.inMemory, AccessMode.throughDedicatedWorker));
@@ -390,15 +385,21 @@ final class DatabaseClient implements WebSqlite {
390385
}
391386
}
392387

393-
if (_connectionToShared case final connection?) {
394-
final response = await connection.sendRequest(
395-
CompatibilityCheck(
396-
requestId: 0,
397-
type: MessageType.sharedCompatibilityCheck,
398-
databaseName: databaseName,
399-
),
400-
MessageType.simpleSuccessResponse,
401-
);
388+
Future<void> sharedCompatibilityCheck(WorkerConnection connection) async {
389+
SimpleSuccessResponse response;
390+
try {
391+
response = await connection.sendRequest(
392+
CompatibilityCheck(
393+
requestId: 0,
394+
type: MessageType.sharedCompatibilityCheck,
395+
databaseName: databaseName,
396+
),
397+
MessageType.simpleSuccessResponse,
398+
);
399+
} on Object {
400+
return;
401+
}
402+
402403
final result = CompatibilityResult.fromJS(response.response as JSObject);
403404

404405
if (result.canUseIndexedDb) {
@@ -423,6 +424,13 @@ final class DatabaseClient implements WebSqlite {
423424
}
424425
}
425426

427+
if (_connectionToDedicated case final dedicated?) {
428+
await dedicatedCompatibilityCheck(dedicated);
429+
}
430+
if (_connectionToShared case final shared?) {
431+
await sharedCompatibilityCheck(shared);
432+
}
433+
426434
available.add((StorageMode.inMemory, AccessMode.inCurrentContext));
427435
if (workersReportedIndexedDbSupport || await checkIndexedDbSupport()) {
428436
// If the workers can use IndexedDb, so can we.

sqlite3_web/pubspec.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: sqlite3_web
22
description: Utilities to simplify accessing sqlite3 on the web, with automated feature detection.
3-
version: 0.2.1
3+
version: 0.2.2
44
homepage: https://github.com/simolus3/sqlite3.dart/tree/main/sqlite3_web
55
repository: https://github.com/simolus3/sqlite3.dart
66

sqlite3_web/test/integration_test.dart

+30-15
Original file line numberDiff line numberDiff line change
@@ -108,21 +108,36 @@ void main() {
108108
});
109109

110110
setUp(() async {
111-
final rawDriver = await createDriver(
112-
spec: browser.isChromium ? WebDriverSpec.JsonWire : WebDriverSpec.W3c,
113-
uri: browser.driverUri,
114-
desired: {
115-
'goog:chromeOptions': {
116-
'args': [
117-
'--headless=new',
118-
'--disable-search-engine-choice-screen',
119-
],
120-
},
121-
'moz:firefoxOptions': {
122-
'args': ['-headless']
123-
},
124-
},
125-
);
111+
late WebDriver rawDriver;
112+
for (var i = 0; i < 3; i++) {
113+
try {
114+
rawDriver = await createDriver(
115+
spec: browser.isChromium
116+
? WebDriverSpec.JsonWire
117+
: WebDriverSpec.W3c,
118+
uri: browser.driverUri,
119+
desired: {
120+
'goog:chromeOptions': {
121+
'args': [
122+
'--headless=new',
123+
'--disable-search-engine-choice-screen',
124+
],
125+
},
126+
'moz:firefoxOptions': {
127+
'args': ['-headless']
128+
},
129+
},
130+
);
131+
break;
132+
} on SocketException {
133+
// webdriver server taking a bit longer to start up...
134+
if (i == 2) {
135+
rethrow;
136+
}
137+
138+
await Future.delayed(const Duration(milliseconds: 500));
139+
}
140+
}
126141

127142
// logs.get() isn't supported on Firefox
128143
if (browser != Browser.firefox) {

0 commit comments

Comments
 (0)