flutterfire
flutterfire copied to clipboard
🐛 [firebase_storage] Upload hangs when app is backgrounded on macos
Bug report
I am having trouble with my uploads hanging in a "running" state:
await Firestorage.FirebaseStorage.instance.ref(audioTarget).putFile(audioFile);
I trigger the upload this way, and the upload hangs (application remains responsive) and never completes. I checked the status of the UploadTask using the snapshotEvents
stream: it emits a single TaskSnapshot with the state running
almost immediately and then nothing. Curiously, this only happens if I cmd-tab to a different application while waiting for the upload. If I sit in the app and wait, it completes just fine.
Steps to reproduce
- Start application (main widgets parented by AudioServiceWidget)
- Trigger upload with
Firestore.CollectionReference tracks =
Firestore.FirebaseFirestore.instance.collection('projects/${Settings.firebaseProjectId}/tracks');
return tracks.add(_toFirebaseData(fileData)).then((Firestore.DocumentReference track) async {
var basePath = track.id;
File audioFile = File(audioPath);
var audioTarget = '$basePath/${track.id}.mp3';
await Firestorage.FirebaseStorage.instance.ref(audioTarget).putFile(audioFile);
- After triggering upload, cmd-tab to another application.
- Observe that file put never completes (checked firebase storage dashboard to confirm).
Expected behavior
Upload completes in a reasonable time frame (my test files were from 8k to 2.1mb, they would hang indefinitely or at least 30mins+).
When doing this while keeping the app in foreground, uploads were ~10-15s maximum.
Additional context
- I believe this may be related to the issue I experienced with https://github.com/FirebaseExtended/flutterfire/issues/4267 where having different isolates for the audio player caused some bad behaviour in Firestore, but have not confirmed this. It seems to be a broader problem with isolate communication, based on what I read in https://github.com/FirebaseExtended/flutterfire/issues/4108 and other issues.
- After restarting the app I would see a lot of messages about GTMSessionUploadFetcher "restoring upload fetcher", which I believe to be because the uploader got stuck and was persisted for resume on re-open.
Flutter doctor
Run flutter doctor
and paste the output below:
Click To Expand
[✓] Flutter (Channel dev, 1.26.0-1.0.pre, on macOS 11.0.1 20B29 darwin-x64, locale en-CA)
• Flutter version 1.26.0-1.0.pre at /Users/pschuegr/flutter
• Framework revision 63062a6443 (2 weeks ago), 2020-12-13 23:19:13 +0800
• Engine revision 4797b06652
• Dart version 2.12.0 (build 2.12.0-141.0.dev)
[✓] Android toolchain - develop for Android devices (Android SDK version 30.0.2)
• Android SDK at /Users/pschuegr/Library/Android/sdk
• Platform android-30, build-tools 30.0.2
• Java binary at: /Applications/Android Studio.app/Contents/jre/jdk/Contents/Home/bin/java
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)
• All Android licenses accepted.
[✓] Xcode - develop for iOS and macOS (Xcode 12.3)
• Xcode at /Applications/Xcode.app/Contents/Developer
• Xcode 12.3, Build version 12C33
• CocoaPods version 1.10.0
[✓] Android Studio (version 4.1)
• Android Studio at /Applications/Android Studio.app/Contents
• Flutter plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/9212-flutter
• Dart plugin can be installed from:
🔨 https://plugins.jetbrains.com/plugin/6351-dart
• Java version OpenJDK Runtime Environment (build 1.8.0_242-release-1644-b3-6915495)
[✓] VS Code (version 1.52.1)
• VS Code at /Applications/Visual Studio Code.app/Contents
• Flutter extension version 3.18.0
[✓] Connected device (2 available)
• Pixel 3a (mobile) • 92SAY040D9 • android-arm64 • Android 11 (API 30)
• macOS (desktop) • macos • darwin-x64 • macOS 11.0.1 20B29 darwin-x64
Flutter dependencies
Run flutter pub deps -- --style=compact
and paste the output below:
Click To Expand
Dart SDK 2.12.0-141.0.dev
Flutter SDK 1.26.0-1.0.pre
calliope 0.0.1+2
dependencies:
- args 1.6.0
- audio_service 0.16.0 [audio_session rxdart flutter_isolate flutter_cache_manager sqflite js flutter flutter_web_plugins]
- audio_session 0.0.10 [flutter flutter_web_plugins rxdart]
- cloud_firestore 0.14.4 [flutter meta quiver firebase_core firebase_core_platform_interface cloud_firestore_platform_interface cloud_firestore_web]
- cupertino_icons 1.0.2
- firebase_auth 0.18.4+1 [meta firebase_core firebase_core_platform_interface firebase_auth_platform_interface firebase_auth_web flutter]
- firebase_core 0.5.3 [firebase_core_platform_interface flutter quiver meta firebase_core_web]
- firebase_storage 5.2.0 [flutter firebase_core firebase_core_platform_interface firebase_storage_web firebase_storage_platform_interface quiver]
- flutter 0.0.0 [characters collection meta typed_data vector_math sky_engine]
- google_sign_in 4.5.6 [google_sign_in_platform_interface flutter meta google_sign_in_web]
- just_audio 0.6.3 [just_audio_platform_interface just_audio_web audio_session rxdart path path_provider async uuid flutter]
- path 1.8.0-nullsafety.3
- provider 4.3.2+3 [collection flutter nested]
- shared_preferences 0.5.12+4 [meta flutter shared_preferences_platform_interface shared_preferences_linux shared_preferences_macos shared_preferences_web shared_preferences_windows]
- util 0.0.0 [chunked_stream dart_numerics]
- uuid 2.2.2 [crypto convert]
- watcher 0.9.7+15 [async path pedantic]
dev dependencies:
- flutter_test 0.0.0 [flutter test_api path fake_async clock stack_trace vector_math async boolean_selector characters charcode collection matcher meta source_span stream_channel string_scanner term_glyph typed_data]
transitive dependencies:
- archive 2.0.13 [crypto args path]
- async 2.5.0-nullsafety.3 [collection]
- boolean_selector 2.1.0-nullsafety.3 [source_span string_scanner]
- characters 1.1.0-nullsafety.5
- charcode 1.2.0-nullsafety.3
- chunked_stream 1.1.0
- clock 1.1.0-nullsafety.3
- cloud_firestore_platform_interface 2.2.1 [flutter meta collection firebase_core plugin_platform_interface]
- cloud_firestore_web 0.2.1+2 [flutter flutter_web_plugins http_parser meta firebase_core firebase_core_web cloud_firestore_platform_interface js]
- collection 1.15.0-nullsafety.5
- convert 2.1.1 [charcode typed_data]
- crypto 2.1.5 [collection convert typed_data]
- dart_numerics 0.0.5 [tuple]
- fake_async 1.2.0-nullsafety.3 [clock collection]
- ffi 0.1.3
- file 5.2.1 [intl meta path]
- firebase_auth_platform_interface 2.1.4 [flutter meta firebase_core plugin_platform_interface]
- firebase_auth_web 0.3.2+3 [flutter flutter_web_plugins meta http_parser intl firebase_core firebase_core_web firebase_auth_platform_interface js]
- firebase_core_platform_interface 2.1.0 [flutter meta plugin_platform_interface quiver]
- firebase_core_web 0.2.1+1 [firebase_core_platform_interface flutter flutter_web_plugins meta js]
- firebase_storage_platform_interface 1.0.2 [flutter meta collection firebase_core plugin_platform_interface]
- firebase_storage_web 0.1.1+1 [async crypto firebase_core firebase_core_web firebase_storage_platform_interface flutter flutter_web_plugins http js meta]
- flutter_cache_manager 2.1.0 [flutter path_provider uuid http path sqflite pedantic clock file rxdart image]
- flutter_isolate 1.0.0+14 [flutter uuid]
- flutter_web_plugins 0.0.0 [flutter js characters collection meta typed_data vector_math]
- google_sign_in_platform_interface 1.1.2 [flutter meta quiver]
- google_sign_in_web 0.9.2 [google_sign_in_platform_interface flutter flutter_web_plugins meta js]
- http 0.12.2 [http_parser path pedantic]
- http_parser 3.1.4 [charcode collection source_span string_scanner typed_data]
- image 2.1.19 [archive xml meta]
- intl 0.16.1 [path]
- js 0.6.3-nullsafety.3
- just_audio_platform_interface 2.0.0 [flutter meta plugin_platform_interface]
- just_audio_web 0.2.1 [just_audio_platform_interface flutter flutter_web_plugins meta]
- matcher 0.12.10-nullsafety.3 [stack_trace]
- meta 1.3.0-nullsafety.6
- nested 0.0.4 [flutter]
- path_provider 1.6.24 [flutter path_provider_platform_interface path_provider_macos path_provider_linux path_provider_windows]
- path_provider_linux 0.0.1+2 [path xdg_directories path_provider_platform_interface flutter]
- path_provider_macos 0.0.4+6 [flutter]
- path_provider_platform_interface 1.0.4 [flutter meta platform plugin_platform_interface]
- path_provider_windows 0.0.4+3 [path_provider_platform_interface meta path flutter ffi win32]
- pedantic 1.9.2 [meta]
- petitparser 3.1.0 [meta]
- platform 2.2.1
- plugin_platform_interface 1.0.3 [meta]
- process 3.0.13 [file intl meta path platform]
- quiver 2.1.5 [matcher meta]
- rxdart 0.25.0
- shared_preferences_linux 0.0.2+4 [file flutter meta path path_provider_linux shared_preferences_platform_interface]
- shared_preferences_macos 0.0.1+11 [shared_preferences_platform_interface flutter]
- shared_preferences_platform_interface 1.0.4 [meta flutter]
- shared_preferences_web 0.1.2+7 [shared_preferences_platform_interface flutter flutter_web_plugins meta]
- shared_preferences_windows 0.0.1+3 [shared_preferences_platform_interface flutter ffi file meta path path_provider_platform_interface path_provider_windows]
- sky_engine 0.0.99
- source_span 1.8.0-nullsafety.4 [charcode collection path term_glyph]
- sqflite 1.3.2+1 [flutter sqflite_common path]
- sqflite_common 1.0.2+1 [synchronized path meta]
- stack_trace 1.10.0-nullsafety.6 [path]
- stream_channel 2.1.0-nullsafety.3 [async]
- string_scanner 1.1.0-nullsafety.3 [charcode source_span]
- synchronized 2.2.0+2
- term_glyph 1.2.0-nullsafety.3
- test_api 0.2.19-nullsafety.6 [async boolean_selector collection meta path source_span stack_trace stream_channel string_scanner term_glyph matcher]
- tuple 1.0.3 [quiver]
- typed_data 1.3.0-nullsafety.5 [collection]
- vector_math 2.1.0-nullsafety.5
- win32 1.7.4 [ffi]
- xdg_directories 0.1.2 [meta path process]
- xml 4.5.1 [collection convert meta petitparser]
Hi @pschuegr Can you please provide a minimal complete reproducible code sample? Thank you
@markusaksli-nc https://github.com/pschuegr/firebase_upload
This required the use of the audio_service plugin, so https://github.com/ryanheise/audio_service/issues/477 may be relevant.
Hi @pschuegr Can you please provide a code sample without using the third-party package, you can upload a local image and see if it reproduce the issue, please provide that code sample Thank you
I wasn't able to easily reproduce without the audio_service plugin. Does using a third-party lib cause problems for you?
Hi @pschuegr
If you can reproduce using local assets or without using third-party packages it would be a firebase_storage package issue otherwise. It's hard to pinpoint the cause, you said it doesn't reproduce without using audio_service
It's possible that this is an issue with the audio_service plugin, but given that there are a number of issues (ie https://github.com/FirebaseExtended/flutterfire/issues/3671, https://github.com/FirebaseExtended/flutterfire/issues/4267, https://github.com/FirebaseExtended/flutterfire/issues/4108) filed about problems with background isolates in FlutterFire, I think there's also a reasonable chance that this is another effect of that. I'm unsure if the fix by @ened in https://github.com/FirebaseExtended/flutterfire/pull/4209 would have any effect on cloud storage since it seems to be targeted at firestore.
@ryanheise may have a better understanding of this, I'll see if I can bring it to his attention (not sure if tagging him is enough).
Unfortunately I do not have time right now to dig in and see if I can reproduce this without using another plugin, it seems highly likely that I could do so using similar behaviour with background isolates. However, at minimum I think the firebase_storage package should do what it can to handle this more gracefully and indicate to the user that something has gone wrong. (Sorry my understanding of isolates and communication is not great).
@ryanheise may have a better understanding of this, I'll see if I can bring it to his attention (not sure if tagging him is enough).
I would just contribute two quick points.
- @TahaTesser , If @pschuegr is right in his assessment (which seems likely), then this bug is in firebase_storage and the only way to reproduce it would be through the aid of an additional plugin outside of firebase_storage. The reason is that bugs of this sort only manifest themselves when the buggy plugin (in this case firebase_storage) is run inside of a secondary FlutterEngine, and the only way to create that secondary FlutterEngine is via some additional plugin (such as audio_service). @pschuegr has provided references to similar issues of this sort to give you some background about the nature of this sort of bug.
- @pschuegr , It is going to be difficult for someone (either from Google or the wider community) to investigate it without a reproduction project. Since all you should need to recreate the necessary conditions is a secondary FlutterEngine, the simplest plugin you can use to create that would be the flutter_isolate package. See this comment for my advice on how you could create such a minimal reproduction project.
@ryanheise Good points,
@pschuegr Please a provide minimal complete reproducible code sample? Thank you
@TahaTesser I'm unconvinced that I can make this happen with less code than https://github.com/pschuegr/firebase_upload/blob/master/lib/main.dart and to be honest I am still not clear on why this is necessary, since the intent of a minimal reproduction is generally to avoid burning developer time trying to reproduce the problem. Can you explain?
Apologies if this comes off as confrontational, but IMO figuring out the the answer to questions like "what else causes this problem? what is the underlying cause?" is best done by somebody who has an understanding of the code already. I'm under the impression that FlutterFire is a funded project, so presumably there is somebody whose job it is to do this already? Please correct me if I've misunderstood and this is a volunteer effort.
Would it be preferable if I used the flutter_isolate
package to reproduce this? If so I'll have a crack at it.
The code in firebase_storage is affected by the same bug that #4209 fixed in cloud_firestore: https://github.com/FirebaseExtended/flutterfire/blob/master/packages/firebase_storage/firebase_storage/ios/Classes/FLTFirebaseStoragePlugin.m#L104.
This will for sure need some work and cleanup.
IMO there is no need for further repro cases.
@Salakar FYI
It may be of interest to mention that I am moving audio_service away from the multi-FlutterEngine model and toward a single shared FlutterEngine model (see https://github.com/ryanheise/audio_service/issues/415). There are just too many problematic plugins that don't know how to function correctly in the presence of multiple FlutterEngines. This move will help side step the problem in a big way, and in audio_service's case will also result in faster audio service startup times. (Although if your app uses other plugins that also create additional FlutterEngines, like android_alarm_manager, you will still have to face this larger issue head on.)
Is there an update on a pr to fix this, or some workaround? I'm still facing this issue
@andy-t-wang FYI, will take a look at this issue next.
@ened Hey just checking in has this been fixed?
This issue is not fixed yet, and how is the fix going ? I am using firebase_storage: 10.0.1
Experiencing this issue too.
Same issue here.
same
Anyone found a fix for this?
To everyone saying "me too" or "any progress", please read the above response https://github.com/firebase/flutterfire/issues/4513#issuecomment-756092432 which asks:
Please a provide minimal complete reproducible code sample?
That's where it's still at. If you would like to help move things forward, please do that.
My project contains the following dependencies:
firebase_auth: ^3.4.1
firebase_core: ^1.19.1
firebase_storage: ^10.3.1
cloud_firestore: ^3.2.1
cloud_functions: ^3.3.1
flutter_isolate: ^2.0.2
isolate_handler: ^1.0.1
And whenever I try to upload a file it just hangs on ios, never returning the result for the upload even tho the file actually uploads (It works normally on android).
It hangs in this line of my code await bucket.ref(path).putFile(file, settableMetadata);
When I remove the isolates related dependency it works just fine!
flutter_isolate: ^2.0.2
isolate_handler: ^1.0.1
Is there a sample app for us to try that?
Is there a sample app for us to try that?
No there isn't - that's the very thing that you are being asked to create yourself and provide a link to (if you want to help this bug progress). All the people who could potentially fix this are likely busy working on other bugs or features or apps that they are not going to divert their attention to this at least until someone provides a minimal reproduction project (or if you're lucky, the fix itself).
FYI, it's very easy to create a small project which reproduces this problem which fits my definition of "minimal completely reproducible", and IIRC I did so (had to edit it out of the original bug report because it had some open firebase project that I didn't want to leave up), but because it used a third-party lib I assume the concern was that the bug could be in the third party lib and thus a waste of developer time to chase it.
My instinct says that this is an issue with firebase_storage and how it interacts with isolates, but I have only a thin knowledge of Dart to start off with, so shrug take that for what it's worth.
Hey @pschuegr. We need more information to resolve this issue but there hasn't been an update in 7 weekdays. I'm marking the issue as stale and if there are no new updates in the next 7 days I will close it automatically.
If you have more information that will help us get to the bottom of this, just add a comment!
Since there haven't been any recent updates here, I am going to close this issue.
@pschuegr if you're still experiencing this problem and want to continue the discussion just leave a comment here and we are happy to re-open this.
I'm currently experiencing the same issue.
await bucket.ref(path).putFile(file, settableMetadata);
Will hang on the await on iOs (Android works just fine). I've also tried streaming the response and it still doesn't work on iOs (again android works just fine).
The biggest difference are:
- I'm not running the
putFile
function directly in an isolate, its in an asynchronous function - I'm not directly using the package
flutter_isolate: ^2.0.2
, maybe one of my other dependencies is or they are using isolates in the same manner as that package.
It looks like no one is willing to work on this until a minimal complete reproducible code sample is provided, which is a bummer. I'll try to get one going so you can find the bug.
The issue is not fixed then. Maybe leaving this comment will get it re-opened?