OutOfMemoryError with Firestore request done on a CoroutineWorker

106 views Asked by At

For my application I need to get some data in background from Firestore every 24h. To do so I implemented a CoroutineWorker that will run every 24H triggered when the phone is charging and that the network is good.

Everything works well for most of the user but for a small part of them I got an OutOfMemory from the collection.get().

Some interesting information is that 48% of the crash happened on PIXEL phone it doesn't seems to reflect the market share. (49 other percent being on samsung phone).

Also 46% of the crash are on Android 13 and 41% on Android 12.

Here is the crash :

Fatal Exception: java.lang.OutOfMemoryError: Firestore (24.2.2) ran out of memory. Check your queries to make sure they are not loading an excessive amount of data.
       at com.google.firebase.firestore.util.AsyncQueue.lambda$panic$3(AsyncQueue.java:529)
       at com.google.firebase.firestore.util.AsyncQueue(AsyncQueue.java)
       at com.google.firebase.firestore.util.AsyncQueue$$InternalSyntheticLambda$0.run(AsyncQueue.java:2)
       at android.os.Handler.handleCallback(Handler.java:942)
       at android.os.Handler.dispatchMessage(Handler.java:99)
       at android.os.Looper.loopOnce(Looper.java:226)
       at android.os.Looper.loop(Looper.java:313)
       at android.app.ActivityThread.main(ActivityThread.java:8741)
       at java.lang.reflect.Method.invoke(Method.java)
       at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
       at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)

And this is my Coroutine worker :

@HiltWorker
class DatabaseSyncWorker @AssistedInject constructor(
    @Assisted val context: Context,
    @Assisted workerParams: WorkerParameters) : CoroutineWorker(context, workerParams) {

    override suspend fun doWork(): Result {

        // Crash Log here are display on firebase crashlytics
        val result = FirebaseFirestore.getInstance().collection("event")
            .orderBy("updated", Query.Direction.ASCENDING)
            .whereArrayContains("some_array_key", "some_array_value")
            .limit(10)
            .get().await().documents
        // Crash Log here are NOT display on firebase crashlytics

        // Doing something with that data here

        return Result.success()
    }

    companion object {
        const val TAG = "DatabaseSyncWorker"

        fun startIfNeeded(context: Context) {
            val constraintBuilder = Constraints.Builder()
                .setRequiredNetworkType(NetworkType.UNMETERED)
                .setRequiresBatteryNotLow(true)
                .setRequiresCharging(true)

            val constraints = constraintBuilder.build()
            val periodicWorkRequest = PeriodicWorkRequest.Builder(DatabaseSyncWorker::class.java, 24, TimeUnit.HOURS)
                .setConstraints(constraints)
                .build()
            WorkManager.getInstance(context).enqueueUniquePeriodicWork(TAG, ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest)
        }
    }
    
}

My first idea was to reduce the amount of data and implem pagination, but I still got them even when requesting as low as 10 items pear page. I can also see from the crash log that it's crashing at the request of the first page.

0

There are 0 answers