Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MultiExecutor is not working now. #2323

Open
YeungKC opened this issue Feb 20, 2023 · 5 comments
Open

MultiExecutor is not working now. #2323

YeungKC opened this issue Feb 20, 2023 · 5 comments

Comments

@YeungKC
Copy link
Contributor

YeungKC commented Feb 20, 2023

I forgot from which version, our app sometimes encounters the error Unhandled Exception: Operation was cancelled, but recently it has become more and more frequent. We finally found out that it was caused by MultiExecutor, but we really need parallel queries (some queries are too slow).

Below is our code for creating the database.

Future<Database> connectToDatabase({
  bool fromMainIsolate = false,
}) async {
  const writePortName = 'write';
  const readPortName = 'read';

  final isolates = await Future.wait([
    _crateIsolate(
      writePortName,
      fromMainIsolate: fromMainIsolate,
    ).then((value) => value.connect()),
    ...List.generate(
        4,
        (index) => _crateIsolate(
              '$readPortName$index',
              fromMainIsolate: fromMainIsolate,
            ).then((value) => value.connect())),
  ]);


  final executor = isolates[0].withExecutor(MultiExecutor.withReadPool(
    reads: isolates.skip(1).toList(),
    write: isolates[0],
  ));

  return Database(executor);
}

Future<DriftIsolate> _crateIsolate(
  String name, {
  bool fromMainIsolate = true,
}) async {
  if (fromMainIsolate) {
    // Remove port if it exists. to avoid port leak on hot reload.
    IsolateNameServer.removePortNameMapping(name);
  }

  final existedSendPort = IsolateNameServer.lookupPortByName(name);

  if (existedSendPort == null) {
    assert(fromMainIsolate, 'Isolate should be created from main isolate');

    final directory = (await getApplicationDocumentsDirectory()).path;
    String path = p.join(directory, 'db.sqlite');

    final dbFile = File(path);

    final driftIsolate = await DriftIsolate.spawn(
        () => LazyDatabase(() => NativeDatabase(dbFile, setup: (rawDb) {
              rawDb
                ..execute('PRAGMA journal_mode=WAL;')
                ..execute('PRAGMA foreign_keys=ON;')
                ..execute('PRAGMA synchronous=NORMAL;');
            })));

    IsolateNameServer.registerPortWithName(driftIsolate.connectPort, name);
    return driftIsolate;
  } else {
    return DriftIsolate.fromConnectPort(existedSendPort, serialize: false);
  }
}

stack trace:

[ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: Operation was cancelled
#0      checkIfCancelled (package:drift/src/runtime/cancellation_zone.dart:91:5)
#1      _BaseExecutor._runRequest (package:drift/src/remote/client_impl.dart:87:5)
#2      _BaseExecutor.runSelect (package:drift/src/remote/client_impl.dart:130:26)
#3      DatabaseConnection.runSelect (package:drift/src/runtime/api/connection.dart:108:16)
#4      _QueryExecutorPool._run (package:drift/src/runtime/executor/connection_pool.dart:97:10)
#5      _QueryExecutorPool.runSelect (package:drift/src/runtime/executor/connection_pool.dart:77:5)
#6      _MultiExecutorImpl.runSelect (package:drift/src/runtime/executor/connection_pool.dart:146:26)
#7      SimpleSelectStatement._getRaw.<anonymous closure> (package:drift/src/runtime/query_builder/statements/select/select.dart:68:16)
#8      DatabaseConnectionUser.doWhenOpened.<anonymous closure> (package:drift/src/runtime/api/connection_user.dart:162:64)
#9      _rootRunUnary (dart:async/zone.dart:1406:47)
#10     _CustomZone.runUnary (dart:async/zone.dart:1307:19)
<asynchronous suspension>
#11     NonNullableCancellationExtension.resultOrNullIfCancelled (package:drift/src/runtime/cancellation_zone.dart:62:24)
<asynchronous suspension>
#12     QueryStream.fetchAndEmitData (package:drift/src/runtime/executor/stream_queries.dart:315:20)
<asynchronous suspension>

demo: https://github.com/YeungKC/drift_issue_2323

@simolus3
Copy link
Owner

Thanks for the report! I'll need to investigate this further, do you get a stack trace for the Operation was cancelled errors?

@YeungKC
Copy link
Contributor Author

YeungKC commented Feb 21, 2023

I updated demo and stack trace. Please check it.

@YeungKC
Copy link
Contributor Author

YeungKC commented Feb 27, 2023

@simolus3

This is very important to us. Do you have any ideas?

@simolus3
Copy link
Owner

@YeungKC Sorry for the delay! Your example works with b137b40, can you check if that also fixes the problem in your app?

@YeungKC
Copy link
Contributor Author

YeungKC commented Feb 28, 2023

@simolus3

The commit works fine in the demo without any CancellationException, but it is still occurring in our project which is much more complex.

I am still trying to reproduce it in the demo.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants