firebase / flutterfire

🔥 A collection of Firebase plugins for Flutter apps.
https://firebase.google.com/docs/flutter/setup
BSD 3-Clause "New" or "Revised" License
8.67k stars 3.97k forks source link

Firestore transaction timeout parameter in runTransaction does not work #9118

Closed inamaze44 closed 1 year ago

inamaze44 commented 2 years ago

I have a problem with my transaction timeouts. The timeout always takes around 9 seconds independent of how I set the timeout parameter.

final db = FirebaseFirestore.instance;
final docref = db.collection('appdata').doc(docID);
final data = {'rueckruf': FieldValue.serverTimestamp()};

db.runTransaction((transaction) async {
  transaction.update(docref, data);
}, timeout: Duration(seconds: 3)).then((value) {
  //transaction did work do sth.                         
}, onError: (e) {
  //transaction did not work do sth.
});    
darshankawar commented 2 years ago

@inamaze44 When opening an issue, try to use new issue template and fill out requested details so that we'll have enough details to work with. Looking at code you shared, we can't analyze properly. Can you provide flutter doctor -v, plugin version and complete minimal reproducible code sample along with current and expected behavior ?

inamaze44 commented 2 years ago

The Link on the page: https://pub.dev/packages/cloud_firestore on the bottom: Please file FlutterFire specific issues, bugs, or feature requests in our issue tracker (https://github.com/firebase/flutterfire/issues/new) took me to a blank entry form. I suggest to change the link to https://github.com/firebase/flutterfire/issues/new/choose so I would have chosen the right form.

inamaze44 commented 2 years ago

I will fill out a new form with all the information then.

darshankawar commented 2 years ago

on the bottom: Please file FlutterFire specific issues, bugs, or feature requests in our issue tracker (https://github.com/firebase/flutterfire/issues/new) took me to a blank entry form. I suggest to change the link to https://github.com/firebase/flutterfire/issues/new/choose

Thanks for pointing this out. I'll forward this to concerned team for the fix.

Meanwhile:

Can you provide flutter doctor -v, plugin version and complete minimal reproducible code sample along with current and expected behavior ?

inamaze44 commented 2 years ago

Bug report

Firestore transaction timeout parameter in runTransaction does not work

Steps to reproduce

Steps to reproduce the behavior:

  1. Login with FirebaseAuth
  2. Put the mobile in Flight mode
  3. Execute the runTransaction command with any data
  4. The transaction timeout always happens after around 10 seconds.

Expected behavior

The transaction timeout should come around the time specified. In the sample the timeout happens after 10 seconds, and not after the 3 seconds specified with the timeout parameter.

Sample project

final db = FirebaseFirestore.instance; final docref = db.collection('appdata').doc(docID); final data = {'rueckruf': FieldValue.serverTimestamp()};

db.runTransaction((transaction) async { transaction.update(docref, data); }, timeout: Duration(seconds: 3)).then((value) { //transaction did work do sth.
}, onError: (e) { //transaction did not work do sth. });

Additional context

I have updated to the latest versions and I still get that error.


Flutter doctor

Run flutter doctor and paste the output below:

Click To Expand ``` Doctor summary (to see all details, run flutter doctor -v): [✓] Flutter (Channel beta, 3.1.0-9.0.pre, on macOS 12.4 21F79 darwin-arm, locale de-DE) [✓] Android toolchain - develop for Android devices (Android SDK version 32.0.0) [✓] Xcode - develop for iOS and macOS (Xcode 13.3) [✓] Chrome - develop for the web [✓] Android Studio (version 2021.2) [✓] Connected device (3 available) [✓] HTTP Host Availability • No issues found! ```

Flutter dependencies

Run flutter pub deps -- --style=compact and paste the output below:

Click To Expand ``` Dart SDK 2.18.0-165.1.beta Flutter SDK 3.1.0-9.0.pre tk_assistant_app 1.0.0+1 dependencies: - cloud_firestore 3.3.0 [cloud_firestore_platform_interface cloud_firestore_web collection firebase_core firebase_core_platform_interface flutter meta] - cupertino_icons 1.0.5 - firebase_auth 3.4.2 [firebase_auth_platform_interface firebase_auth_web firebase_core firebase_core_platform_interface flutter meta] - firebase_core 1.19.2 [firebase_core_platform_interface firebase_core_web flutter meta] - flutter 0.0.0 [characters collection material_color_utilities meta vector_math sky_engine] - font_awesome_flutter 10.1.0 [flutter] - modal_progress_hud_nsn 0.2.1 [flutter] - rflutter_alert 2.0.4 [flutter] dev dependencies: - flutter_lints 2.0.1 [lints] - flutter_test 0.0.0 [flutter test_api path fake_async clock stack_trace vector_math async boolean_selector characters collection matcher material_color_utilities meta source_span stream_channel string_scanner term_glyph] transitive dependencies: - async 2.9.0 [collection meta] - boolean_selector 2.1.0 [source_span string_scanner] - characters 1.2.1 - clock 1.1.0 - cloud_firestore_platform_interface 5.6.0 [collection firebase_core flutter meta plugin_platform_interface] - cloud_firestore_web 2.7.0 [cloud_firestore_platform_interface collection firebase_core firebase_core_web flutter flutter_web_plugins js] - collection 1.16.0 - fake_async 1.3.0 [clock collection] - firebase_auth_platform_interface 6.3.2 [firebase_core flutter meta plugin_platform_interface] - firebase_auth_web 4.0.0 [firebase_auth_platform_interface firebase_core firebase_core_web flutter flutter_web_plugins http_parser intl js meta] - firebase_core_platform_interface 4.4.3 [collection flutter flutter_test meta plugin_platform_interface] - firebase_core_web 1.7.0 [firebase_core_platform_interface flutter flutter_web_plugins js meta] - flutter_web_plugins 0.0.0 [flutter js characters collection material_color_utilities meta vector_math] - http_parser 4.0.1 [collection source_span string_scanner typed_data] - intl 0.17.0 [clock path] - js 0.6.4 - lints 2.0.0 - matcher 0.12.11 [stack_trace] - material_color_utilities 0.1.5 - meta 1.8.0 - path 1.8.2 - plugin_platform_interface 2.1.2 [meta] - sky_engine 0.0.99 - source_span 1.9.0 [collection path term_glyph] - stack_trace 1.10.0 [path] - stream_channel 2.1.0 [async] - string_scanner 1.1.1 [source_span] - term_glyph 1.2.0 - test_api 0.4.9 [async boolean_selector collection meta source_span stack_trace stream_channel string_scanner term_glyph matcher] - typed_data 1.3.1 [collection] - vector_math 2.1.2 ```

darshankawar commented 2 years ago

2. Put the mobile in Flight mode

@inamaze44 Does the reported behavior only occur in this case ? or also happens when you have proper / stable network ?

inamaze44 commented 2 years ago

I have only tested it in this case, when I have no network.

darshankawar commented 2 years ago

Ok, can you test with WIFI ON and flight mode OFF and see if you still get same behavior ?

inamaze44 commented 2 years ago

My transaction only takes a fraction of a second to fulfill. When I have WIFI on and flight mode OFF the transaction finishes successfully after less than a second and a timeout is neither needed nor called.

Ehesp commented 2 years ago

Transactions do not work offline - is it throwing an error after the 10 second mark? I'd of thought it should throw an error if it has no network connectivity, but it might be seeing if it comes back online during that time period.

inamaze44 commented 2 years ago

I know, that Transactions don't work offline. That is why I am using them. I want to make sure something is written into the database. The timout parameter should also reflect the time trying for a connection.

darshankawar commented 2 years ago

Keeping this issue open for further insights from the team on expected behavior.

inamaze44 commented 2 years ago

@Ehesp I am sorry, I did not answer your question. After that 10 seconds of trying the error message is: [cloud_firestore/unavailable] The service is currently unavailable. This is a most likely a transient condition and may be corrected by retrying with a backoff.

darshankawar commented 2 years ago

[cloud_firestore/unavailable] The service is currently unavailable. This is a most likely a transient condition and may be corrected by retrying with a backoff.

For this error, you'll need to follow-up in same discussion thread: https://github.com/firebase/flutterfire/discussions/5708

inamaze44 commented 2 years ago

@darshankawar I think the other discussion thread does not apply, because the error I get is justified! Because I am offline!

inamaze44 commented 2 years ago

I want the error message to come! But after the time I specified in the timeout parameter.

Ehesp commented 2 years ago

Thanks - makes sense. I suspect this is an upstream issue on the native platform sdks (will raise as an issue if so), but we'll confirm first

russellwheatley commented 2 years ago

Hi @inamaze44, which platform is this happening on?

inamaze44 commented 2 years ago

Hi @russellwheatley! I have this behaviour on my real IPhone13 in flight mode.

russellwheatley commented 2 years ago

hmmmm, I've checked this on android as well and it also doesn't respect the timeout if in flight mode. It doesn't respect it if I set the latency on the emulator to higher than the transaction timeout. I don't think this API works as intended and isn't something that is available on the native SDKs either. Even if we called an exception in the transaction handler on the native side, it would still retry (if maxAttempts are set > 0) when we would be responding with a "timeout" exception.

My preference isn't to fix this, but to remove it. It doesn't work, isn't a Firebase SDK API and is misleading as far as I can tell.

Thoughts, @Lyokone?

inamaze44 commented 2 years ago

Why not ask the firebase team to make the parameter available? Somewhere in their code must be the number 9 or 10 seconds as a timeout. Why not make it available for other packages like ours to change it?

inamaze44 commented 2 years ago

I did not find the parameter maxAttemps as described in the cloud_firestore package api description. I had the idea to set it to less than 5 to reduce the number of 9 seconds but in the version I am using, 3.3.0 it does not seem to have the parameter maxAttempts.

Lyokone commented 2 years ago

hmmmm, I've checked this on android as well and it also doesn't respect the timeout if in flight mode. It doesn't respect it if I set the latency on the emulator to higher than the transaction timeout. I don't think this API works as intended and isn't something that is available on the native SDKs either. Even if we called an exception in the transaction handler on the native side, it would still retry (if maxAttempts are set > 0) when we would be responding with a "timeout" exception.

My preference isn't to fix this, but to remove it. It doesn't work, isn't a Firebase SDK API and is misleading as far as I can tell.

Thoughts, @Lyokone?

Yeah, it could probably be brought up to Firebase to see if implementing in the native SDK could be done. Does Firestore Transaction give a cancel token? I don't see why we couldn't implement the timeout ourselves if it is, but I only see a way to abort a transaction from inside

russellwheatley commented 2 years ago

@Lyokone As far as I can tell, there is no way of aborting. You can't even cancel (i.e. throwing an exception within the transaction function) it running as it will simply retry until the amount set via maxAttempts has been reached.

@inamaze44 The latest Firestore version has maxAttempts: https://github.com/firebase/flutterfire/blob/master/packages/cloud_firestore/cloud_firestore/lib/src/firestore.dart#L230

inamaze44 commented 2 years ago

I updated to the latest Firestore version and did some experiments with maxAttempts. maxAttempts is actually referring to the local attempts and not (only) to the attempts on the server. In FlightMode maxAttempts = 1 had 0 seconds until the error message appeared, which makes sense. maxAttempts = 1 -> error after 0s maxAttempts = 2 -> error after ~2s maxAttempts = 3 -> error after ~3s maxAttempts = 4 -> error after ~4s maxAttempts = 5 -> error after ~9s <- well known 9s maxAttempts = 6 -> error after ~13s maxAttempts = 7 -> error after ~21s maxAttempts = 8 -> error after ~24s maxAttempts = 9 -> error after ~47s maxAttempts = 10 -> error after ~82s maxAttempts = 11 -> error after ~145s It looks like and exponential function, at least not linear.

By pointing out maxAttempts you have solved my problem! I will set maxAttempts to 3 and have a comfortable localTimeout of 3 seconds in FlightMode. Thank you!!!

I think the timeout parameter refers to the timeout on the server (which I have not tested), how long the transaction is maximally allowed to take on the server, and thus the parameter also makes sense. It would be good to point that out in the documentation.

Lyokone commented 1 year ago

I'm closing this according to the last message.