simolus3 / drift

Drift is an easy to use, reactive, typesafe persistence library for Dart & Flutter.
https://drift.simonbinder.eu/
MIT License
2.54k stars 362 forks source link

Add easy isolate-shared NativeDatabases #3118

Closed clragon closed 1 month ago

clragon commented 1 month ago

Is your feature request related to a problem? Please describe. My application runs background tasks at various points in time. Sometimes while the foreground isolate is also running. To prevent errors, these two have to share their Drift database connection. Doing all that requires quite a bit of setup on my side.

In my specific case this looks something like this:


DatabaseConnection connectDatabase(String name) {
  return DatabaseConnection.delayed(
    Future(
      () async {
        final key = 'database-isolate-$name';
        RootIsolateToken? token = RootIsolateToken.instance;
        DriftIsolate isolate;

        SendPort? sendPort = IsolateNameServer.lookupPortByName(key);
        if (sendPort != null) {
          isolate = DriftIsolate.fromConnectPort(sendPort);
        } else {
          isolate = await DriftIsolate.spawn(
            () => LazyDatabase(
              () async {
                if (token == null) {
                  throw StateError('RootIsolateToken is not initialized!');
                }
                BackgroundIsolateBinaryMessenger.ensureInitialized(token);

                return NativeDatabase(
                  File(
                    join(
                      (await getApplicationSupportDirectory()).path,
                      name,
                    ),
                  ),
                );
              },
            ),
          );
        }

        return isolate.connect();
      },
    ),
  );
}

Describe the solution you'd like

It would be nice if the NativeDatabase class featured a constructor that automatically did all of this, namely:

NativeDatabases which are bound to files specifically benefit from this process as not sharing them leads to file lock and data desync issues.

There is also the concern of when to close the database. For my purposes it would be okay if the isolate shut down when all connections are gone.

frankvollebregt commented 1 month ago

~I guess it's difficult for a feature like this to fit as many use-cases as possible.~

~Drift does already offer some ways to work with isolates out-of-the-box without requiring additional setup. I.e. for running a single heavy operation in the background, you can use computeWithDatabase from https://drift.simonbinder.eu/docs/advanced-features/isolates/#simple-sharing~

~And if you want to instead run everything through an isolate you can use functions like createInBackground or even with a MultiExecutor.~

~Admittedly, my own database setup looks quite a bit like yours (though a bit more convoluted I think), so perhaps there is merit in having something like this...~

clragon commented 1 month ago

Apologies, I dont quite understand what youre trying to say.

The, in my opinion considerable, usecase of this feature is to make it very easy to share a database between the foreground flutter isolate and any backgound isolates, spawned by e.g. workmanager.

I am well aware of createInBackground and I have used it since this issue. However, this creates a independant isolate each time, which will lead to the above mentioned conflicts, which is why my setup looks like the code above, since yesterday.

computeWithDatabase and MultiExecutor are nice, but I am unsure how they would help me cut down my setup.

So, implementing a simplification for this wouldn't fit "many" usescases but rather just one large usecase.

simolus3 commented 1 month ago

Having a feature that allows easily sharing a drift database between isolates that aren't otherwise talking to each other sounds like a useful addition. Closing an isolate after all clients have disconnected and then automatically re-opening it sounds like a useful addition too. The core drift package is platform-agnostic and can't depend on dart:ui or Flutter, so we can't use IsolateNameServer there. This could go into the drift_flutter package though.

clragon commented 1 month ago

Excellent, thank you!