Firebase Remote Configの挙動について
Remote Configは便利なんですが雰囲気で使うと思ったように動かなかったりするのでちゃんとまとめようと思います.
TL;DL
- fetchAndActivateをするとremoteの値がローカルに保存され参照可能となる
- ローカルキャッシュの期限は最短でも12分でそれ以上の頻度では更新できない
- 参照は通信結果ではなく常にローカルキャッシュの値
概要
図1. RemoteConfig概要図[1]
抑えておきたい概念は以下の通り
- cache
- fetch/activate
- interval
1個ずつ見ていきます.
cache
Remote Configは常にremoteから値を取得するわけではなく,後述するfetchIntervalにlimitがありそれ以上の頻度ではremoteの値を取得できない仕組みになっています.なので基本的にはローカルのキャッシュを参照してたまにremoteの値を取得すると思ってもらって良いです.Device File Explorerでローカルフォルダを見に行くと以下のようにjsonが保存されていて参照するときはこの値を見ています.(any_key_nameとなってるところがRemote Configで設定したフィールド名で今回はboolを設定していると思ってください)
frc_1/xxxxxxxxxxx/android/xxxxxxxxxxx_firebase_activate.json
{"configs_key":{"any_key_name":"true"},"fetch_time_key":1593480378652,"abt_experiments_key":[]}
ex.kt
remoteConfig.getBoolean("any_key_name")
fetchの設定やログもxmlで保持しています.
frc_1/xxxxxxxxxxx/android/xxxxxxxxxxx_firebase_settings.xml
<?xml version='1.0' encoding='utf-8' standalone='yes' ?> <map> <long name="fetch_timeout_in_seconds" value="5" /> <int name="last_fetch_status" value="-1" /> <boolean name="is_developer_mode_enabled" value="false" /> <long name="minimum_fetch_interval_in_seconds" value="1800" /> <long name="backoff_end_time_in_millis" value="-1" /> <long name="last_fetch_time_in_millis" value="1593480378652" /> <int name="num_failed_fetches" value="0" /> </map>
fetch/activate
cacheの項目でアプリはactivateされたcacheを参照すると記述しましたがfetchを行っただけではjsonファイルは作成されません.fetchをした段階では以下のようなファイルがローカルのdataディレクトリに作成されます,このjsonはremoteの情報を反映したものです.
frc_1/xxxxxxxxxxx/android/xxxxxxxxxxx_firebase_fetch.json
{"configs_key":{"any_key_name":"false"},"fetch_time_key":1593829520560,"abt_experiments_key":[]}
以下のようにactivateすることで初めてfirebase_activate.jsonが作成されます.
return activatedConfigsCache .put(fetchedContainer) .continueWith(executor, this::processActivatePutTask);
return Tasks.call(executorService, () -> storageClient.write(configContainer))
interval
上述のとおりintervalはremoteからフェッチする間隔であり公式によると最短で1時間5回(=12分)のようです.
アプリが短期間に何度もフェッチすると、フェッチ呼び出しが抑制され、SDK から FirebaseRemoteConfigFetchThrottledException が返されます。バージョン 17.0.0 よりも前の SDK では、フェッチ リクエストは 60 分間に 5 回までと制限されていました(新しいバージョンでは制限が緩和されています)。 Android で Firebase Remote Config を使ってみる
デフォルトではインターバルは12時間に設定されます.
public static final long DEFAULT_MINIMUM_FETCH_INTERVAL_IN_SECONDS = HOURS.toSeconds(12);
firebase-android-sdk/ConfigFetchHandler.java at master · firebase/firebase-android-sdk · GitHub
キャッシュの有効期限(=インターバル)が切れていなければローカルの値を読みます.
if (cachedFetchConfigsTask.isSuccessful() && areCachedFetchConfigsValid(minimumFetchIntervalInSeconds, currentTime)) { // Keep the cached fetch values if the cache has not expired yet. return Tasks.forResult(FetchResponse.forLocalStorageUsed(currentTime)); }
firebase-android-sdk/ConfigFetchHandler.java at master · firebase/firebase-android-sdk · GitHub
また,なんらかの理由でremoteのfetchに失敗した場合はエクスポネンシャルバックオフでスロットリングがかかるのでその場合もfetchは行われないようです(exceptionが吐かれる)
Date backoffEndTime = getBackoffEndTimeInMillis(currentTime); if (backoffEndTime != null) { // TODO(issues/260): Provide a way for users to check for throttled status so exceptions // aren't the only way for users to determine if they're throttled. fetchResponseTask = Tasks.forException( new FirebaseRemoteConfigFetchThrottledException( createThrottledMessage(backoffEndTime.getTime() - currentTime.getTime()), backoffEndTime.getTime())); } else {
まとめ
仕組みがわかれば特に難しいことはないんですが雰囲気で使うとremoteの値が取得できないとか思った結果と違うものが取得できたみたいなことになりやすいです.最短でも12分間隔でしかfetchできないというのがミソなのでリアルタイム性が求められるような情報はRemote Configとはあまり相性が良くないと言えるかもしれません.