Viddyut Khanvilkar
Viddyut Khanvilkar

Reputation: 295

Flutter app crashes on concurrent transactions performed on cloud Firestore

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.

Upvotes: 2

Views: 1787

Answers (2)

eldermao
eldermao

Reputation: 673

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.

Upvotes: 1

Frank van Puffelen
Frank van Puffelen

Reputation: 598728

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.

Upvotes: 1

Related Questions