Skip to content

Commit cb7672b

Browse files
committed
Fix handling worker errors
1 parent a290e87 commit cb7672b

File tree

5 files changed

+89
-54
lines changed

5 files changed

+89
-54
lines changed

sqlite3_web/CHANGELOG.md

Lines changed: 4 additions & 0 deletions
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

Lines changed: 10 additions & 2 deletions
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

Lines changed: 44 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -305,16 +305,10 @@ final class DatabaseClient implements WebSqlite {
305305

306306
Future<void> _startDedicated() async {
307307
if (globalContext.has('Worker')) {
308-
final Worker dedicated;
309-
try {
310-
dedicated = Worker(
311-
workerUri.toString().toJS,
312-
WorkerOptions(name: 'sqlite3_worker'),
313-
);
314-
} on Object {
315-
_missingFeatures.add(MissingBrowserFeature.dedicatedWorkers);
316-
return;
317-
}
308+
final dedicated = Worker(
309+
workerUri.toString().toJS,
310+
WorkerOptions(name: 'sqlite3_worker'),
311+
);
318312

319313
final (endpoint, channel) = await createChannel();
320314
ConnectRequest(endpoint: endpoint, requestId: 0).sendToWorker(dedicated);
@@ -328,14 +322,8 @@ final class DatabaseClient implements WebSqlite {
328322

329323
Future<void> _startShared() async {
330324
if (globalContext.has('SharedWorker')) {
331-
final SharedWorker shared;
332-
try {
333-
shared = SharedWorker(workerUri.toString().toJS);
334-
shared.port.start();
335-
} on Object {
336-
_missingFeatures.add(MissingBrowserFeature.sharedWorkers);
337-
return;
338-
}
325+
final shared = SharedWorker(workerUri.toString().toJS);
326+
shared.port.start();
339327

340328
final (endpoint, channel) = await createChannel();
341329
ConnectRequest(endpoint: endpoint, requestId: 0).sendToPort(shared.port);
@@ -398,15 +386,22 @@ final class DatabaseClient implements WebSqlite {
398386
final available = <(StorageMode, AccessMode)>[];
399387
var workersReportedIndexedDbSupport = false;
400388

401-
if (_connectionToDedicated case final connection?) {
402-
final response = await connection.sendRequest(
403-
CompatibilityCheck(
404-
requestId: 0,
405-
type: MessageType.dedicatedCompatibilityCheck,
406-
databaseName: databaseName,
407-
),
408-
MessageType.simpleSuccessResponse,
409-
);
389+
Future<void> dedicatedCompatibilityCheck(
390+
WorkerConnection connection) async {
391+
SimpleSuccessResponse response;
392+
try {
393+
response = await connection.sendRequest(
394+
CompatibilityCheck(
395+
requestId: 0,
396+
type: MessageType.dedicatedCompatibilityCheck,
397+
databaseName: databaseName,
398+
),
399+
MessageType.simpleSuccessResponse,
400+
);
401+
} on Object {
402+
return;
403+
}
404+
410405
final result = CompatibilityResult.fromJS(response.response as JSObject);
411406
existing.addAll(result.existingDatabases);
412407
available.add((StorageMode.inMemory, AccessMode.throughDedicatedWorker));
@@ -440,15 +435,21 @@ final class DatabaseClient implements WebSqlite {
440435
}
441436
}
442437

443-
if (_connectionToShared case final connection?) {
444-
final response = await connection.sendRequest(
445-
CompatibilityCheck(
446-
requestId: 0,
447-
type: MessageType.sharedCompatibilityCheck,
448-
databaseName: databaseName,
449-
),
450-
MessageType.simpleSuccessResponse,
451-
);
438+
Future<void> sharedCompatibilityCheck(WorkerConnection connection) async {
439+
SimpleSuccessResponse response;
440+
try {
441+
response = await connection.sendRequest(
442+
CompatibilityCheck(
443+
requestId: 0,
444+
type: MessageType.sharedCompatibilityCheck,
445+
databaseName: databaseName,
446+
),
447+
MessageType.simpleSuccessResponse,
448+
);
449+
} on Object {
450+
return;
451+
}
452+
452453
final result = CompatibilityResult.fromJS(response.response as JSObject);
453454

454455
if (result.canUseIndexedDb) {
@@ -473,6 +474,13 @@ final class DatabaseClient implements WebSqlite {
473474
}
474475
}
475476

477+
if (_connectionToDedicated case final dedicated?) {
478+
await dedicatedCompatibilityCheck(dedicated);
479+
}
480+
if (_connectionToShared case final shared?) {
481+
await sharedCompatibilityCheck(shared);
482+
}
483+
476484
available.add((StorageMode.inMemory, AccessMode.inCurrentContext));
477485
if (workersReportedIndexedDbSupport || await checkIndexedDbSupport()) {
478486
// If the workers can use IndexedDb, so can we.

sqlite3_web/pubspec.yaml

Lines changed: 1 addition & 1 deletion
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.2-dev
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

Lines changed: 30 additions & 15 deletions
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)