Reaktive: Freezing issue

I’m trying to track down a freezing issue on iOS when using reaktive streams, and pared down the issue with a new sample project.

It seems the call to mutate() below is causing ShimTester to be frozen, but I thought using threadLocal would prevent that. Is my current usage correct? What’s the correct way to call mutate() in the example below?

KN code:


class ShimTester {

    init {
        expectEnsureNeverFrozenShim()
    }

    fun mutate() { }

    fun testApiWrapper(): ObservableWrapper<Unit> {
        return testApi()
                .subscribeOn(mainScheduler)
                .observeOn(mainScheduler)
                .threadLocal()
                .wrap()
    }

    fun testApi(): Observable<Unit> {
        return observableFromFunction {
            mutate()

            Unit
        }
    }
}

On iOS, I’m using:

        ShimTester().testApiWrapper().subscribe(
            isThreadLocal: true,
            onSubscribe: nil,
            onError: nil,
            onComplete: nil) { unit in
                print("Done")
        }

This causes an exception:

Uncaught exception: kotlin.native.concurrent.FreezingException: 
 freezing of [com.badoo.reaktive.scheduler.MainScheduler.ExecutorImpl.Operation@1e25bc8] has failed,
 first blocker is ...ShimTester@1daa928kotlin.native.concurrent.FreezingException:
 freezing of [com.badoo.reaktive.scheduler.MainScheduler.ExecutorImpl.Operation@1e25bc8] has failed,
 first blocker is ..ShimTester@1daa928

I tried moving threadLocal further upstream, before mutate(), but hit the same freeze exception:

class ShimTester {

    ...

    fun testApi(): Observable<Unit> {
        return observableOf(5)
                .subscribeOn(mainScheduler)
                .observeOn(mainScheduler)
                .threadLocal()
                .map {
                    mutate()
                    Unit
                }
    }
}

About this issue

  • Original URL
  • State: closed
  • Created 4 years ago
  • Comments: 22 (12 by maintainers)

Most upvoted comments

Hey, it’s hard to understand why is it frozen, the fix may help. It may be frozen by Reaktive or by SQLDelight. But in general I would not expect the listener to be not frozen, and just design the app in such a way. You can try querying database in the following way:

db
    .testQueries
    .select()
    .listenForChanges()
    .observeOn(mainScheduler)
    .subscribe(isThreadLocal = true) {
        // Use the data
    }

Or like this:

    network
        .loadData()
        .observeOn(ioScheduler)
        .doOnBeforeSuccess { 
            db.saveData(it) // Blocking call
        }
        .observeOn(mainScheduler)
        .subscribe(isThreadLocal = true) {
            // Use the data
        }    

You can find some useful SQLDelight extensions here.

Please note, I did not try yet the provided code above in Kotlin/Native. But it should work assuming SQLDelight is freezable (unlike Ktor). I hope it is freezable.

Actually there is a bug. The following code should work but it crashes in iOS:

class ShimTester {

    init {
        ensureNeverFrozen()
    }

    fun mutate() {
    }

    fun testApi() {
        observableOf(5)
            .filter { true }
            .map {
                mutate()
                Unit
            }
            .observeOn(mainScheduler)
            .subscribe()
    }
}

I will fix this. Thanks for raising the issue!

Btw ensureNeverFrozen is available in reaktive-utils module. As well as isFrozen extension property.

Thanks, I think I am unblocked for now since attaching the onComplete and onError handlers seem to prevent this freeze error, will reply back if I still run into it.