Firestore transaction latency, huge difference between web and mobile

Viewed 58

I couple of months ago I decided to use flutter/firebase/firestore on a brand new app. I started to develop it for the web platform and everything was ok about the firestore performances. Now I'm developing the android version (basically it's the same code for all the DB services) and the firestore performances are not good at all.

Concretely, I observe a huge difference when running the same transaction (same wifi connection) on any web browser and on android devices.

On the web, it takes less than 150ms to run it :

js_primitives.dart:47 @@@Before transaction 2022-04-25 11:25:11.539 js_primitives.dart:47 @@@Start transaction 2022-04-25 11:25:11.573 js_primitives.dart:47 @@@After seed get 2022-04-25 11:25:11.637 js_primitives.dart:47 @@@after tag get 2022-04-25 11:25:11.638 js_primitives.dart:47 @@@after set counter 2022-04-25 11:25:11.639 js_primitives.dart:47 @@@after set plant 2022-04-25 11:25:11.643 js_primitives.dart:47 @@@after set tag 2022-04-25 11:25:11.644 js_primitives.dart:47 @@@after set post 2022-04-25 11:25:11.645 js_primitives.dart:47 @@@After transaction 2022-04-25 11:25:11.718

On a galaxy j6 with android 10, it takes 2.5 seconds to run it :

I/flutter (10627): @@@Before transaction 2022-04-25 08:58:44.577700 I/flutter (10627): @@@Start transaction 2022-04-25 08:58:44.619733 I/flutter (10627): @@@After seed get 2022-04-25 08:58:47.067945 I/flutter (10627): @@@after tag get 2022-04-25 08:58:47.068416 I/flutter (10627): @@@after set counter 2022-04-25 08:58:47.068670 I/flutter (10627): @@@after set plant 2022-04-25 08:58:47.068998 I/flutter (10627): @@@after set tag 2022-04-25 08:58:47.069214 I/flutter (10627): @@@after set post 2022-04-25 08:58:47.069472

On a galaxy A40 with android 11, it takes more that 12 seconds :

I/flutter (30636): @@@Before transaction 2022-04-2415:38:43.237485 I/flutter (30636): @@@Start transaction 2022-04-24 15:38:43.549120 I/flutter (30636): @@@After seed get 2022-04-24 15:38:49.340047 I/flutter (30636): @@@after tag get 2022-04-24 15:38:49.341779 I/flutter (30636): @@@after set counter 2022-04-24 15:38:49.342491 I/flutter (30636): @@@after set plant 2022-04-24 15:38:49.377040 I/flutter (30636): @@@after set tag 2022-04-24 15:38:49.377556 I/flutter (30636): @@@after set post 2022-04-24 15:38:49.391190 I/flutter (30636): @@@After transaction 2022-04-2415:38:55.602388

Here the code sample for the transaction :

Future<doc.Plant> sowInNursery({
    required String farmName,
    required String specieName,
    required String varietyName,
    required String providerName,
    required String seedId,
    required Timestamp dateTime,
    String? tagName,
    int? quantity,
    String? farmPhotoUrl,
    required String farmerUid,
    String? farmerPhotoUrl,
    String? farmerDisplayName,
    Timestamp? seedReproductionDateTime,
    required String languageCode,
  }) async {
    late DocumentReference tagDocumentReference;
    if (tagName != null) {
      tagDocumentReference = getTagDocumentReference(farmName, tagName);
    }
    DocumentReference seedDocumentReference = getSeedDocumentReference(
        farmName, specieName, varietyName, providerName, seedId);
    DocumentReference plantDocumentReference =
        getPlantDocumentReferenceWithAutoGeneratedId(
            farmName, specieName, varietyName, providerName, seedId);
    DocumentReference counterDocumentReference = getCounterDocumentReference(
        farmName, specieName, varietyName, dateTime);
    DocumentReference postDocumentReference =
        getPostDocumentReferenceWithAutoGeneratedId(farmName);

    doc.Plant plant = doc.Plant(
        farm: farmName,
        specie: specieName,
        variety: varietyName,
        provider: providerName,
        seed: seedId,
        name: plantDocumentReference.id,
        seedReproductionDateTime: seedReproductionDateTime,
        stages: doc.Stages(
            nurserySowedStage: doc.NurserySowedStage(
                dateTime: dateTime,
                tag: tagName,
                farmerUid: farmerUid,
                stockItem: doc.StockItem.forNurserySowing(quantity))))
      ..lifecycleStages = [pb.LifecycleStage.NURSERY_SOWED]
      ..plantActions = [pb.PlantAction.SOW_IN_NURSERY];
    doc.Post post = doc.Post(
        farm: farmName,
        name: postDocumentReference.id,
        dateTime: dateTime,
        updateDateTime: dateTime,
        farmerUid: farmerUid,
        farmerPhotoUrl: farmPhotoUrl,
        farmerDisplayName: farmerDisplayName,
        farmPhotoUrl: farmPhotoUrl,
        stagePostType: doc.StagePostType(
            counterLifecycleStage: pb.CounterLifecycleStage.NURSERY_SOWINGS,
            specie: specieName,
            variety: varietyName,
            stockItem: doc.StockItem.forTransplant(quantity)));

    doc.Plant document =
        await firebaseService.firestore.runTransaction((transaction) async {
      print("@@@Start transaction ${DateTime.now()}");
      // Read the seed doc
      DocumentSnapshot seedSnapshot =
          await transaction.get(seedDocumentReference);
      if (!seedSnapshot.exists) {
        throw Exception("La graine ${seedDocumentReference.id} n'existe pas");
      }
      doc.Seed seed =
          doc.Seed.fromJson(seedSnapshot.data()! as Map<String, dynamic>);
      print("@@@After seed get ${DateTime.now()}");

     
      // Read the tag doc
      late doc.Tag tag;
      if (tagName != null) {
        DocumentSnapshot tagSnapshot =
            await transaction.get(tagDocumentReference);
        if (!tagSnapshot.exists) {
          throw Exception(
              "L'étiquette ${tagDocumentReference.id} n'existe pas");
        }
        tag = doc.Tag.fromJson(tagSnapshot.data()! as Map<String, dynamic>);
      }
      print("@@@after tag get ${DateTime.now()}");

      // Update the counter doc
      if (quantity != null) {
        DocumentSnapshot counterSnapshot =
            await transaction.get(counterDocumentReference);
        doc.Counter? counter;
        if (counterSnapshot.exists) {
          counter = doc.Counter.fromJson(
              counterSnapshot.data()! as Map<String, dynamic>);
        }
        counter = updateCounterDocument(
            counter,
            farmName,
            specieName,
            varietyName,
            counterDocumentReference.id,
            1,
            doc.StockItem.forNurserySowing(quantity)!,
            pb.CounterLifecycleStage.NURSERY_SOWINGS);
        transaction.set(counterDocumentReference, counter.toJson());
      }
      print("@@@after set counter ${DateTime.now()}");

      // Create the plant doc
      transaction.set(plantDocumentReference, plant.toJson());
      print("@@@after set plant ${DateTime.now()}");

      // Update the tag doc
      if (tagName != null) {
        tag.taggedPlants.add(doc.TaggedPlant(
            plant: doc.Plant(
              farm: farmName,
              specie: specieName,
              variety: varietyName,
              provider: providerName,
              seed: seedId,
              name: plantDocumentReference.id,
            ),
            counter: 1));
        transaction.set(tagDocumentReference, tag.toJson());
      }
      print("@@@after set tag ${DateTime.now()}");

      // Create the post doc
      transaction.set(postDocumentReference, post.toJson());
      print("@@@after set post ${DateTime.now()}");

      return plant;
    });
    return document;
  }
0 Answers
Related