Skip to content

Commit f2d668f

Browse files
committed
Fix web database not respecting lock timeouts
1 parent 016e341 commit f2d668f

File tree

3 files changed

+25
-5
lines changed

3 files changed

+25
-5
lines changed

packages/sqlite_async/lib/src/web/database.dart

+2-2
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ class WebDatabase
8686
Future<T> readLock<T>(Future<T> Function(SqliteReadContext tx) callback,
8787
{Duration? lockTimeout, String? debugContext}) async {
8888
if (_mutex case var mutex?) {
89-
return await mutex.lock(() async {
89+
return await mutex.lock(timeout: lockTimeout, () async {
9090
final context = _SharedContext(this);
9191
try {
9292
return await callback(context);
@@ -135,7 +135,7 @@ class WebDatabase
135135
Future<T> writeLock<T>(Future<T> Function(SqliteWriteContext tx) callback,
136136
{Duration? lockTimeout, String? debugContext, bool? flush}) async {
137137
if (_mutex case var mutex?) {
138-
return await mutex.lock(() async {
138+
return await mutex.lock(timeout: lockTimeout, () async {
139139
final context = _ExclusiveContext(this);
140140
try {
141141
return await callback(context);

packages/sqlite_async/lib/src/web/web_mutex.dart

+2-3
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,9 @@ external Navigator get _navigator;
1616
/// Web implementation of [Mutex]
1717
class MutexImpl implements Mutex {
1818
late final mutex.Mutex fallback;
19-
String? identifier;
2019
final String resolvedIdentifier;
2120

22-
MutexImpl({this.identifier})
21+
MutexImpl({String? identifier})
2322

2423
/// On web a lock name is required for Navigator locks.
2524
/// Having exclusive Mutex instances requires a somewhat unique lock name.
@@ -40,7 +39,7 @@ class MutexImpl implements Mutex {
4039

4140
@override
4241
Future<T> lock<T>(Future<T> Function() callback, {Duration? timeout}) {
43-
if ((_navigator as JSObject).hasProperty('locks'.toJS).toDart) {
42+
if (_navigator.has('locks')) {
4443
return _webLock(callback, timeout: timeout);
4544
} else {
4645
return _fallbackLock(callback, timeout: timeout);

packages/sqlite_async/test/basic_test.dart

+21
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,27 @@ void main() {
209209
expect(await db.get('SELECT description FROM test_data'),
210210
{'description': 'test'});
211211
});
212+
213+
test('respects lock timeouts', () async {
214+
// Unfortunately this test can't use fakeAsync because it uses actual
215+
// lock APIs on the web.
216+
final db = await testUtils.setupDatabase(path: path);
217+
final lockAcquired = Completer();
218+
219+
final completion = db.writeLock((context) async {
220+
lockAcquired.complete();
221+
await Future.delayed(const Duration(seconds: 1));
222+
});
223+
224+
await lockAcquired.future;
225+
await expectLater(
226+
() => db.writeLock(
227+
lockTimeout: Duration(milliseconds: 200), (_) async => {}),
228+
throwsA(isA<TimeoutException>()),
229+
);
230+
231+
await completion;
232+
});
212233
});
213234
}
214235

0 commit comments

Comments
 (0)