问题
I am trying to develop an app where multiple users log in and completes a poll concurrently.
In this, as soon as user submits the answer the transaction is ran to increment the counter for given answer
try {
DocumentSnapshot freshsnap = await tx.get(reff);
try {
await tx.update(reff, <String, dynamic>{
'$i': freshsnap['$i'] + 1,
});
} catch (error) {
print("Error" + error.code);
}
} catch (error) {
if (error is PlatformException &&
error.code == 'Error performing transaction') {
// await tx.set(ref, data);
print("Error" + error.code);
} else
rethrow;
}
}).catchError((onError){
print("Error on: "+onError);
});
as soon as the multiple users submit the same answer for same question concurrently i.e The same field in same document is requested to update by multiple users concurrently the app crashes and generates following error:
FATAL EXCEPTION: AsyncTask #1
E/AndroidRuntime(12169): Process: com.rrcg.tumerboared, PID: 12169
E/AndroidRuntime(12169): java.lang.RuntimeException: An error occurred while executing doInBackground()
E/AndroidRuntime(12169): at android.os.AsyncTask$3.done(AsyncTask.java:354)
E/AndroidRuntime(12169): at java.util.concurrent.FutureTask.finishCompletion(FutureTask.java:383)
E/AndroidRuntime(12169): at java.util.concurrent.FutureTask.setException(FutureTask.java:252)
E/AndroidRuntime(12169): at java.util.concurrent.FutureTask.run(FutureTask.java:271)
E/AndroidRuntime(12169): at android.os.AsyncTask$SerialExecutor$1.run(AsyncTask.java:245)
E/AndroidRuntime(12169): at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
E/AndroidRuntime(12169): at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
E/AndroidRuntime(12169): at java.lang.Thread.run(Thread.java:764)
E/AndroidRuntime(12169): Caused by: java.lang.AssertionError: INTERNAL ASSERTION FAILED: A transaction object cannot be used after its update callback has been invoked.
E/AndroidRuntime(12169): at com.google.firebase.firestore.util.Assert.fail(com.google.firebase:firebase-firestore@@21.2.1:46)
E/AndroidRuntime(12169): at com.google.firebase.firestore.util.Assert.hardAssert(com.google.firebase:firebase-firestore@@21.2.1:31)
E/AndroidRuntime(12169): at com.google.firebase.firestore.core.Transaction.ensureCommitNotCalled(com.google.firebase:firebase-firestore@@21.2.1:246)
E/AndroidRuntime(12169): at com.google.firebase.firestore.core.Transaction.lookup(com.google.firebase:firebase-firestore@@21.2.1:81)
E/AndroidRuntime(12169): at com.google.firebase.firestore.Transaction.getAsync(com.google.firebase:firebase-firestore@@21.2.1:191)
E/AndroidRuntime(12169): at com.google.firebase.firestore.Transaction.get(com.google.firebase:firebase-firestore@@21.2.1:228)
E/AndroidRuntime(12169): at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$5.doInBackground(CloudFirestorePlugin.java:550)
E/AndroidRuntime(12169): at io.flutter.plugins.firebase.cloudfirestore.CloudFirestorePlugin$5.doInBackground(CloudFirestorePlugin.java:545)
E/AndroidRuntime(12169): at android.os.AsyncTask$2.call(AsyncTask.java:333)
E/AndroidRuntime(12169): at java.util.concurrent.FutureTask.run(FutureTask.java:266)
E/AndroidRuntime(12169): ... 4 more
Have no idea why is this happening, since transaction should allow multiple users to update a field of a document concurrently.
回答1:
If you are running on a physical iOS device, the crash is caused by this bug in the FlutterFire binding library. There doesn't seem to be a workaround, so keep an eye on the issue for updates.
回答2:
I solved this by making the transaction object (tx) non-async and moving the async logic outside the transaction block. After all, the whole point of transactions is to execute its instructions atomically and async instructions kind of defeat this purpose.
来源:https://stackoverflow.com/questions/59051694/flutter-app-crashes-on-concurrent-transactions-performed-on-cloud-firestore