Remote Config - FirebaseRemoteConfigFetchThrottledException but interval is not short
Describe your environment
- Android Studio version: Android Studio Iguana | 2023.2.1 Patch 2
- Firebase Component: Remote Config (Database, Firestore, Storage, Functions, etc)
- Component version: 32.6.0 (BoM)
Describe the problem
We just deployed Remote Config to production following the steps based in here: https://firebase.google.com/docs/remote-config/get-started?platform=android
After deploying, we got a crash on a One Plus 8 Pro device (Android 11) for the following:
Fatal Exception: com.google.firebase.remoteconfig.FirebaseRemoteConfigFetchThrottledException: Fetch is throttled. Please wait before calling fetch again: 01:07
at com.google.firebase.remoteconfig.FirebaseRemoteConfigException.<init>(FirebaseRemoteConfigException.java:28)
at com.google.firebase.remoteconfig.FirebaseRemoteConfigFetchThrottledException.<init>(FirebaseRemoteConfigFetchThrottledException.java:43)
at com.google.firebase.remoteconfig.internal.ConfigFetchHandler.fetchIfCacheExpiredAndNotThrottled(ConfigFetchHandler.java:254)
at com.google.firebase.remoteconfig.internal.ConfigFetchHandler.lambda$fetch$0(ConfigFetchHandler.java:172)
at com.google.android.gms.tasks.zze.run(com.google.android.gms:play-services-tasks@@18.0.2:1)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
at com.google.firebase.concurrent.CustomThreadFactory.lambda$newThread$0(CustomThreadFactory.java:47)
at java.lang.Thread.run(Thread.java:923)
I do not understand how this is occurring though, because our throttle time is set to the default interval of 12 hours and was deployed with such. See code below.
I see that the guide says the following:
Keep in mind that this setting should be used for development only, not for an app running in production. If you're just testing your app with a small 10-person development team, you are unlikely to hit the hourly service-side quota limits. But if you pushed your app out to thousands of test users with a very low minimum fetch interval, your app would probably hit this quota.
but should we not be calling this function / setting AT ALL in production? Even if it's set to the default 12 hours?
I noticed someone else had a similar problem here: https://stackoverflow.com/questions/43805682/firebaseremoteconfigfetchthrottledexception-askfirebase
Steps to reproduce:
What happened? How can we make the problem occur? This could be a description, log/console output, etc.
Relevant Code:
// The following is used in a DI class for obtaining the Firebase remote config object
@Module
@InstallIn(SingletonComponent::class)
object NetworkModule {
@Provides
fun provideFirebaseRemoteConfig(): FirebaseRemoteConfig {
// Manually set to 12 hours like the library default
// Using the constants to easily reconfigure if needed
// https://firebase.google.com/docs/remote-config/get-started?platform=android#throttling
return Firebase.remoteConfig.apply {
setConfigSettingsAsync(
remoteConfigSettings {
minimumFetchIntervalInSeconds = Constants.FIREBASE_REMOTE_CONFIG_INTERVAL
setDefaultsAsync(R.xml.remote_config_defaults)
}
)
}
}
}
Constants.kt
// Remote config recognizes new values given an interval
// e.g. In seconds (3600 = 1 hour)
// Default set to 12 hours like the library default, leaving it here
// in case we want to easily tweak it.
const val FIREBASE_REMOTE_CONFIG_INTERVAL = 43200L
/**
* Obtain firebase remote config values for application
*/
private fun fetchAndActivateRemoteConfig() {
viewModelScope.launch {
val response = remoteConfig.fetchAndActivate().await()
// True: New configs were fetch
// False: No configs were fetched from the backend and the local fetched configs have already been activated
Log.d(TAG, "Firebase Remote Config params updated: $response | Current interval: ${Constants.FIREBASE_REMOTE_CONFIG_INTERVAL} seconds")
}
}
I found a few problems with this issue:
- I couldn't figure out how to label this issue, so I've labeled it for a human to triage. Hang tight.
- This issue does not seem to follow the issue template. Make sure you provide all the required information.
Hi @rwarner, thank you for reaching out. I tried reproducing the issue using our quickstart app, however, I did not encounter the throttling issue. Does the issue occur if you remove the setMinimumFetchIntervalInSeconds setting, or change the value to a lower interval?
Aside from that, are you constantly experiencing this error? Does the issue occur on certain devices and/or android versions? Can you share an MCVE that I can run to help us investigate the issue?
Hey @lehcar09 sorry for the delay. Understandable you couldn't reproduce with the quick start app. I also did not encounter the issue during my development at all. So it was a surprise to me when I saw it in our Crashlytics once we deployed this to production.
Does the issue occur if you remove the setMinimumFetchIntervalInSeconds setting, or change the value to a lower interval?
I am not sure, we only just deployed it with the default 12 hour increment. Would need another release to configure a lower value.
Aside from that, are you constantly experiencing this error? Does the issue occur on certain devices and/or android versions?
After looking at the crashes over the weekend, it seems to only be affecting this one person so far:
- One Plus 8 Pro on Android 11
Can you share an MCVE that I can run to help us investigate the issue?
I unfortunately cannot easily reproduce with my own development. Would you mind confirming if using this setting at all in production is okay?
setMinimumFetchIntervalInSeconds
Should we not be calling this function / setting AT ALL in production? Even if it's set to the default 12 hours?
Thank you!
Based on The setMinimumFetchIntervalInSeconds can be used for production.
Setting the fetch interval value lower than 12hrs, is recommended only for development and/or testing purposes.
Could you check if the fetch fails? Based on this reference, you can encounter throttling for failed backend calls.
Aside from that, I suggest updating to the latest SDK version (BOM 32.8.1). Based on our release notes, there are fixes to the Remote Config updates that might fix the issue.our documentation,
Based on setMinimumFetchIntervalInSeconds can be used for production. Setting the fetch interval value lower than 12hrs, is recommended only for development and/or testing purposes
Okay good to know that we can leave that in there as long as it's at 12 hours.
We did get a few more adoption by users today and I am getting some more exceptions for this same issue. The following other phones came up as well:
- Pixel 4
- One Plus 10 Pro 5G
Each of those phones (Pixel 4, One Plus 8, One Plus 10) also had these same issue come up alongside the first issue:
Fatal Exception: com.google.firebase.remoteconfig.FirebaseRemoteConfigServerException: Fetch failed: The server is unavailable. Please try again later.
at com.google.firebase.remoteconfig.internal.ConfigFetchHandler.createExceptionWithGenericMessage(ConfigFetchHandler.java:457)
at com.google.firebase.remoteconfig.internal.ConfigFetchHandler.fetchFromBackend(ConfigFetchHandler.java:410)
at com.google.firebase.remoteconfig.internal.ConfigFetchHandler.fetchFromBackendAndCacheResponse(ConfigFetchHandler.java:347)
at com.google.firebase.remoteconfig.internal.ConfigFetchHandler.lambda$fetchIfCacheExpiredAndNotThrottled$2(ConfigFetchHandler.java:280)
at com.google.android.gms.tasks.zze.run(com.google.android.gms:play-services-tasks@@18.0.2:1)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at com.google.firebase.concurrent.CustomThreadFactory.lambda$newThread$0(CustomThreadFactory.java:47)
at java.lang.Thread.run(Thread.java:1012)
Caused by com.google.firebase.remoteconfig.FirebaseRemoteConfigServerException: Service Unavailable
at com.google.firebase.remoteconfig.internal.ConfigFetchHttpClient.fetch(ConfigFetchHttpClient.java:205)
at com.google.firebase.remoteconfig.internal.ConfigFetchHandler.fetchFromBackend(ConfigFetchHandler.java:379)
at com.google.firebase.remoteconfig.internal.ConfigFetchHandler.fetchFromBackendAndCacheResponse(ConfigFetchHandler.java:347)
at com.google.firebase.remoteconfig.internal.ConfigFetchHandler.lambda$fetchIfCacheExpiredAndNotThrottled$2(ConfigFetchHandler.java:280)
at com.google.android.gms.tasks.zze.run(com.google.android.gms:play-services-tasks@@18.0.2:1)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
at com.google.firebase.concurrent.CustomThreadFactory.lambda$newThread$0(CustomThreadFactory.java:47)
at java.lang.Thread.run(Thread.java:1012)
Are you thinking it might be a a secondary exception to the actual first problem of the failed fetch?
Aside from that, I suggest updating to the latest SDK version (BOM 32.8.1). Based on our release notes, there are fixes to the Remote Config updates that might fix the issue.our documentation,
I will try updating the BoM to the latest version for our next release and see if this continues. Not sure when we will be able to get our next release out.
Thank you for the additional details you shared, @rwarner. Based on the new stack trace you shared, it looks to me that this is working as intended. As mentioned here:
Fetch's throws a FirebaseRemoteConfigFetchThrottledException:
- The backoff duration from a previous throttled exception has not expired,
- The backend responded with a throttled error, or
- The backend responded with unavailable errors for the last two fetch requests.
That said, I'll be closing this issue for now. Let me know if there's any misunderstanding and/ or we need to reopen this issue for further investigation.
Thanks @lehcar09 understandable then if this is the case. For whatever it's worth, we're seeing a bunch of new errors after adding Remote Config including the ones I put in above. I put in a PR to update the BoM to 32.8.1 hopefully some of these might be resolved? I was surprised they were all popping up considering the minimal implementation no complex code or anything.
Will keep an eye out on our next release with these errors