Open janftmo opened 1 year ago
same issue in release mode, it works fine in debug mode isar: ^3.0.5, flutter 3.7.0
Same error
same issue with isar: ^3.0.5
same issue
I have this problem using a singleton from the db with get_it
I got this error while re-running my build_runner. Not sure if its the same issue with what others are experiencing but once I restarted the app the error disappeared. Am not seeing this error in production though.
I am able to reproduce this error almost every time when running an android physical device in release mode with the inspector set to true by exiting and reopening my app. I have not gone to production yet with my app but I am really hoping this would not be a production issue as we have invested a lot of money into migrating to isar.
I think it has to do with the Isar.open not always returning the current instance and trying to open another one.
We're also seeing this in release mode.
@simc any ideas? It looks like a pretty serious bug that needs attention
It would help a lot if anyone found a way to reproduce this and tell me on which physical device. Otherwise it's very difficult for me to help with this.
Thanks. We will gather as much information as possible and report back.
Hi @simc, I am facing this same issue on a payment terminal(BluePad 5500 Plus) which runs on Android 10. It happens when i close and opens the app mostly in release build. I am also attaching logs screen shot might be helpful. I am using the latest version of isar which is 3.1.0+1.
IsarError: MdbxError (11): Try again
@Joel134 does it happen if you close and immediately reopen the app or even if you wait a short while?
Were you able to reproduce the issue?
@simc Perhaps this happens to be every time even i am facing it now. Moreover when i switch off and then turn on and go back to my app. I get this error and then i used to restart my application which fixes for a while but still occurs when i open and close the app simultaneously.
It would be incredibly helpful if someone found a way to reproduce this. Until then it's very difficult for me to fix
@simc: hope this helps:
I am encountering this message:
I/flutter (29750): ╔══════════════════════════════════════════════════════╗
I/flutter (29750): ║ ISAR CONNECT STARTED ║
I/flutter (29750): ╟──────────────────────────────────────────────────────╢
I/flutter (29750): ║ Open the link to connect to the Isar ║
I/flutter (29750): ║ Inspector while this build is running. ║
I/flutter (29750): ╟──────────────────────────────────────────────────────╢
I/flutter (29750): ║ https://inspect.isar.dev/3.1.0+1/#/56813/4s6_Ena7vbI ║
I/flutter (29750): ╚══════════════════════════════════════════════════════╝
E/flutter (29750): [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: IsarError: Cannot open Environment: MdbxError (11): Try again
i have a service set up before runApp() which calls Isar.open(). When i run the App in debug mode and hot reload the App a couple of times, this error will eventually pop up. Hot reload will recreate my service and therefore call Isar.open multiple times (in the same configuration).
try this as a way to reproduce it by hot reloading:
void() main async {
WidgetsFlutterBinding.ensureInitialized();
final dir = await getApplicationDocumentsDirectory();
await Isar.open([schemas], directory: dir.path);
runApp(MyApp());
}
Same problem here using version 3.1.0+1.
In the logs, this error appears when I go to the background and Isar is saving information while the app is backgrounded; it is not memory related and the device is a Xiaomi Xiaomi 11 Lite 5G NE.
I found this way of using Singleton with Isar and it solves the problem.
class IsarService {
// SINGLETON
static IsarService? _instance;
static IsarService get instance {
_instance ??= IsarService();
return _instance!;
}
late Future<Isar> db;
IsarService() {
db = _openIsar();
}
Future<Isar> _openIsar() async {
if (Isar.getInstance() == null) {
final dir = await getApplicationDocumentsDirectory();
return await Isar.open(
[ChatSchema, SectionSchema, AuthUserSchema],
inspector: !kReleaseMode, directory: dir.path);
}
return Future.value(Isar.getInstance());
}
...
}
I already using Singleton but still get this crash on firebase. But I'm still not able to reproduce it.
Had this issue occur for me today. We use this library for our android "kiosk" devices, so I've tested this library on probably 20-30 devices that are all exactly the same hardware and software wise. (android 7.1, flutter 3.3.7, isar 3.0.5)
It's only ever occurred on one device, and that was today.
I think it occurred after many flutter restarts/hot reloads and many vscode debugger attachment/detachments, which lines up with @FritzMatthaeus comment
My guess is that this is some kind of resource ownership issue, originating from the database instance not getting properly closed/disposed of.
@simc I saw in previous comments that you were suggesting this issue is potentially related to closing/opening the application, so I think it's relevant to note that our app is impossible to close and re-open(due to it being a kiosk-like app).
Similar Issue, Crashlytics reporting problems on multiple devices..... It seems that the problem occurs on specific devices (cpu architectures), on my devices it works fine, but on some devices like my Samsung Tab S2 with Android 6.0 (CPU-arc: armeabi) the problem occurs ......
We have the same problem, Android release version, it seems that the phone model does not matter, it happens on every Android phone. Reproduction:
kill the app, open again, back to normal
code:
final dbFutureProvider = FutureProvider<Isar>((ref) async {
final dir = await getApplicationDocumentsDirectory();
return Isar.open(
[TodoEntitySchema],
directory: dir.path,
name: 'app_db',
);
});
...
Future
await container.read(dbFutureProvider.future);
runApp( UncontrolledProviderScope( container: container, child: const App(), ), ); }
Would anyone be able to provide a small working demo app that shows the issue?
@simc sorry I was wrong, it's not as trivial as I thought. Here you have demo app:
Removing _logger.info('didChangeAppLifecycleState $state');
will fix the problem
We are also running into this problem on our Android apps. This happens on different devices (Nokia and Samsung). It comes up very sporadicly. We use Isar in our apps to handle Firebase FCM messages in the background. Sometimes at random Isar will throw a "IsarError: MdbxError (11): Try again" error.
The logcat output looks like this:
// Irrelevant application logs
08-08 13:45:59.970 2135 2258 E flutter : [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: IsarError: MdbxError (11): Try again
08-08 13:45:59.970 2135 2258 E flutter :
// Irrelevant application logs
08-08 13:46:04.548 2135 2258 I flutter : [38;5;244m[V] 2023-08-08T13:46:04.548287 HandleFirebaseMessage: finished Handling firebase message[0m
08-08 13:46:04.555 2135 2258 E flutter : [ERROR:flutter/runtime/dart_vm_initializer.cc(41)] Unhandled Exception: IsarError: MdbxError (11): Try again
08-08 13:46:04.555 2135 2258 E flutter :
// Irrelevant logs
// Trying to dump the contents of the isar database
08-08 13:48:18.690 2135 2258 I flutter : [38;5;244m[V] 2023-08-08T13:48:18.690137 CreateAppDump: creating messages-box dump[0m
08-08 13:48:18.778 2135 2258 I flutter :[48;5;1mÔöÅÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöü
ÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöü
08-08 13:48:18.778 2135 2258 I flutter : Ôöâ Ôøö failed to create dump file messages-box
08-08 13:48:18.778 2135 2258 I flutter : Ôöâ Error: IsarError: MdbxError (11): Try again
08-08 13:48:18.778 2135 2258 I flutter : ÔöáÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇ
ÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇ
08-08 13:48:18.778 2135 2258 I flutter : Ôöâ Time: 2023-08-08T13:48:18.776857 Ôöé Logger: CreateAppDump
08-08 13:48:18.778 2135 2258 I flutter : ÔöáÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇ
ÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇÔöÇ
08-08 13:48:18.778 2135 2258 I flutter : Ôöâ
08-08 13:48:18.778 2135 2258 I flutter : ÔöùÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöü
ÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöüÔöü [0m
// Irrelevant application logs
Our code for accessing the Isar instance is built like this
import 'dart:io';
import 'package:isar/isar.dart';
import 'package:path/path.dart';
import 'package:path_provider/path_provider.dart';
part 'messages_isar.g.dart';
part 'messages_isar.types.dart';
const String dbName = 'messagesDb';
class MessagesIsarFactory {
MessagesIsarFactory();
Future<Isar> get value async {
final isar = Isar.getInstance(dbName);
if (isar != null) {
if (isar.isOpen) {
return Future.value(isar);
}
}
return Isar.open(
directory: await getDbDirectory().then((directory) => directory.path),
name: dbName,
[
DeterminationCreatedMessageSchema,
DeterminationSubmittedMessageSchema,
PhotoCreatedMessageSchema,
],
);
}
Future<Map<String, dynamic>> dump() async {
final value = await this.value;
return {
'determinationCreatedMessages':
await value.determinationCreatedMessages.dump((value) => value.id),
'determinationSubmittedMessages':
await value.determinationSubmittedMessages.dump((value) => value.id),
'photoCreatedMessages':
await value.photoCreatedMessages.dump((value) => value.id),
};
}
Future<void> dispose() async {
(await value).close();
}
Future<Directory> getDbDirectory() async {
final appDirectory = await getApplicationDocumentsDirectory();
final dbDirectoryPath = joinAll(
[appDirectory.path, 'myapp', 'messages_db'],
);
final dbDirectory = Directory(dbDirectoryPath);
await dbDirectory.create(recursive: true);
return dbDirectory;
}
}
Any help on this would be greatly appreciated. We are moving into production soon and want to keep using Isar.
I have checked crashlytics and found this issue too.
Is there any workaround? Should I ask user to restart the app in case of this error?
@simc sorry I was wrong, it's not as trivial as I thought. Here you have demo app:
- open the app
- use the system back gesture to close the app (not kill)
- click on the app icon again
- you stuck on the splashscreen
- kill the app, open again, back to normal
Removing
_logger.info('didChangeAppLifecycleState $state');
will fix the problem
I can confirm that the issue is reproducible using these steps.
anyone have a workaround for this?
For people still dealing with this. We have desided to remove Isar from our app since this causes app breaking bugs in production. We were able to do this since we only used Isar for handeling messages from Firebase cloud Messaging (Since Isar works cross isolate). Our other data is inside Hive.
We replaced isar with a relatively simple concept where we write every incoming message into a file and store that in a special directory. On that directory we placed a directory watcher so we get notified if a new file appears. As a backup we also manually check the directory at startup and after app resume. In our testing this works great. Hope it helps someone who uses isar for the same use case.
class BackgroundMessagesDirectory {
const BackgroundMessagesDirectory({
required this.fileSystem,
required this.logger,
});
static const String fileName = 'background_messages';
final FileSystem fileSystem;
final Logger logger;
Future<Directory> _getDirectory() async {
final path = await fileSystem
.getTempDirectory()
.then((dir) => join(dir.path, 'background_messages'));
final dir = Directory(path);
if (!await dir.exists()) {
await dir.create(recursive: true);
}
return dir;
}
Future<void> addFirebaseMessage(RemoteMessage message) async {
logger.d('received and storing firebasemessage $message');
final path = await _getDirectory().then((dir) => join(dir.path,
'background_message_${DateTime.now().millisecondsSinceEpoch}'));
final file = File(path);
await file.writeAsString(jsonEncode(message.data), flush: true);
}
Future<Map<String, dynamic>?> readMessage(String path) async {
logger.d('reading message $path');
final file = File(path);
final fileSize = await file.length();
if (fileSize == 0) {
logger.d('empty file encountered $path');
await file.delete();
return null;
}
final contents = await file.readAsString();
Map<String, dynamic>? message;
try {
message = jsonDecode(contents) as Map<String, dynamic>;
logger.d('decoded one message $message');
} catch (exception, stackTrace) {
logger.e('could not parse messages file', exception, stackTrace);
}
await file.delete();
return message;
}
Future<List<Map<String, dynamic>>> readAllMessages() async {
logger.d('Reading all messages');
final dir = await _getDirectory();
final files = await dir.list().toList();
logger.d('found ${files.length} messages');
final messages = <Map<String, dynamic>>[];
for (final file in files) {
final message = await readMessage(file.path);
if (message != null) {
messages.add(message);
}
}
return messages;
}
Stream<WatchEvent> changeEvents({Duration? pollingDelay}) async* {
final dir = await _getDirectory();
yield* DirectoryWatcher(
dir.path,
pollingDelay: pollingDelay ?? const Duration(seconds: 2),
).events.where((event) => event.path.startsWith(dir.path));
}
}
I am sorry to not be able to provide a reproducable expample app. I have encountered a strange Isar behaviour in unit tests. From time to time, running the tests will pause and i assume that it is related to this issue. If i delete the test database files and run the the tests again, they run fine. Until, a couple of test runs later, this occurs again.
I access Isar via a Service Singleton. So Isar.open() is only called once and i keep the Connection open. I do not call isar.close() before closing the app or finishing test runs. Maybe this explains the maxdb error.
Very interesting @FritzMatthaeus.
I also use a singleton and never call isar.close()
.
In my case I add an entry to isar at app launch and I see the issue being logged within 1 or 2 seconds of app start.
I have some stackTraces where the crash is happening while beginning a transaction:
Fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: IsarError: MdbxError (11): Try again
at .nCall(isar_core.dart:174)
at IsarImpl.beginTxnSync(isar_impl.dart:67)
at IsarCommon._beginTxnSync(isar_common.dart:128)
at IsarCommon.getTxnSync(isar_common.dart:170)
at QueryImpl.findSyncInternal(query_impl.dart:72)
at QueryImpl.findFirstSync(query_impl.dart:60)
at QueryExecute.findFirstSync(query_builder_extensions.dart:200)
hopefully this helps giving more ideas for the solution
@simc I did a little investigation and it seems to be a compilation problem for some devices with ARMv7 and Android 10 (91% of cases for me) and in the vast majority Motorola/Samsung/LG. I still don't know if it's a matter of the device's CPU not being able to execute the instructions or if the compiler is not generating correct or inappropriate instructions for these devices. This is just a guess from a little investigation and I could be completely wrong.
Recently the app that my team (@Mairramer is a member of) and I developed was suffering from this context.
The flow actually occurred, but not for the entire base.
I will explain it better below.
Our application has around 500k users, and what happened is that using Isar, we realized that for some bank queries around 3% of our base was being affected.
However, as 3% is a significant number for us, we receive many complaints from customers.
It is important to highlight that we work with inserting 2 to 10 objects into Isar daily and that the average size of each item varies between 100 and 700kb
But by doing a lot of research, we were able to overcome the problem for these users.
I will explain what change we made.
/// THROWING MDBX ERROR IN SOME DEVICES
final collection = await _isar.collection<ExampleModel>();
return collection.filter().statusContains('APPROVED').findAll();
The query above specifically accesses a collection (exampleModel) and applies a filter to it. However, this way, when we are obtaining this IsarCollection, perhaps due to a memory overflow, the error appeared.
/// RESOLUTION
_isar
?.collection<ExampleModel>()
.buildQuery<ExampleModel>(
filter: FilterGroup(
type: FilterGroupType.and,
filters: [const FilterCondition.equalTo(property: 'status', value: 'APPROVED')]),
)
.findAllSync();
For resolution, we started using the query with buildQuery and the necessary FilterConditions.
From this perspective, we noticed that the error stopped occurring
I hope it can help anyone who is being affected by this.
Thanks @pedroafonsouza for sharing!
I have followed your suggestion and it seems the amount of errors have gone down, but I don't have exact numbers to prove it.
I am still experiencing the issue though mainly on LGE and Motorola phones with logs for the following devices:
For me, this error started occurring when I added Firebase Crashlytics to my app. If I remove it, the error stops happening.
@simc
For me this issue persists in isar: ^3.1.0+1
It happens even after the first launch of the app.
I asked the contributors of libmdbx
to know more about the reason of this error.
Their response was as follows.
It is EAGAIN (Resource temporarily unavailable) from a system call. To find out at what operation the system returns this error, you need to enable debug logging via mdbx_setup_debug(). Look in the Isar's docs for how to do this, or ask the author to add such functionality. Alternatively, you can try using the strace utility to at least find out which system call ends with this error.
I don't know how helpful it will be, but hope it does.
@simc sorry I was wrong, it's not as trivial as I thought. Here you have demo app:
- open the app
- use the system back gesture to close the app (not kill)
- click on the app icon again
- you stuck on the splashscreen
- kill the app, open again, back to normal
Removing
_logger.info('didChangeAppLifecycleState $state');
will fix the problemI can confirm that the issue is reproducible using these steps.
I've been having this issue as welI and it specifically happens when I exit the app then go back to it. Because this reply (quoted) sounded very similar to my scenario, I tried removing my code that uses didChangeAppLifecycleState
and found that it works (i.e. I don't get the error)
same issue 🙁🙁🙁
We've noticed this error on our Crashlytics as well. It seems it's limited to low-end devices.
isar: ^3.1.0+1 Our online users have also encountered the same problem, causing them to get stuck in the app startup phase and unable to enter the app, resulting in user loss. About 2-4% of online users have been affected, and I have reproduced this problem once on a oneplus8t (Android 13+14G RAM) phone. This problem is not very easy to reproduce, and I hope developers can solve it
I've implemented a retry mechanism. We'll see if it helps.
@mevljas I am curious, did the retry approach work ?
I'm observing the same issue for several months (since last year). I was always using latest Isar 3.1.0+1
.
I can say with 100% guarantee, that this is only the case on Android and never happens on iOS, which I have validated on ~10M unique sessions every day.
Tried to use raw-query builder as @pedroafonsouza has recommended here, but that didn't help much and the observability hadn't improved on Android.
Then I've added retry to one of the most offending database operations, but that also didn't improve. Maybe in near future I will cover every database operation with retry.
I'm not yet sure if it helped, but we've been mostly observing this issue on opening the database, not other database operations.
Thanks pretty much my same experience: I am experiencing the problem only on Android, mostly on Motorola and LGE phones. I open the database at app launch and I guess on those devices not all resources are ready for it to complete successfully.
I added a retry operation and im still seeing this
I thought it might be down to the fact that android dosnt truly support async write so moved everything over to sync. - this didn't help either.
I keep popping in here to see if there's been a fix or better yet any movement on isar 4 and nothing.
Its now getting to a point where im thinking of moving over to sqflite :(
I am going through the same issue but only for architectures: armeabi-v7a
Same issue here
This issue happen when resumes app back from the AppLifecycleState.detached
, in such case main()
method (where you likely initialize Isar) gets called again.
In order for app to go to the: `AppLifecycleState.detached
state on Android, user needs to click back arrow.
In other words, this issue appears when user clicks back arrow and then resumes app at some point.
I am experiencing the same issue
I wrote a demo to reproduce this issue on an Android phone. When the app returns to the home screen while a database write operation is in progress but not yet completed, and then the app is reopened, this issue occurs.
I've been seeing in FIrebase Crashlytics these errors: Non-fatal Exception: io.flutter.plugins.firebase.crashlytics.FlutterError: IsarError: MdbxError (11): Try again. Error thrown null. at FirebaseCrashlytics.recordError(firebase_crashlytics.dart:119) at CrashlyticsHandler._sendToCrashlytics(crashlytics_handler.dart:48) at CrashlyticsHandler.handle(crashlytics_handler.dart:26) at ExceptionsHandler._reportError(exceptions_handler.dart:87)
Steps to Reproduce
Unfortunately I can't reproduce it on my devices.
There are some devices from Crashlytics which throws this error:
Code sample
I'm using https://pub.dev/packages/injectable for DI.
Details
Similar issue: https://github.com/isar/isar/issues/570