Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

createAtStart should also work when loadKoinModules() is called #801

Closed
bseib opened this issue May 7, 2020 · 5 comments
Closed

createAtStart should also work when loadKoinModules() is called #801

bseib opened this issue May 7, 2020 · 5 comments

Comments

@bseib
Copy link

bseib commented May 7, 2020

Is your feature request related to a problem? Please describe.

In our application we create a bare-bones KoinApplication that knows just enough to assess and setup a local environment to get it into a stable, well known state. Once in that known state, then more modules are loaded, based on the conditions of what happened in the assessment/setup phase. It looks like this:

        val bootstrapModule = module {
            single { AAA(get()) }
            single { BBB() }
            single(createdAtStart = true) { CCC(get()) }
        }
        startKoin {
            modules(bootstrapModule)
        }

        val moduleDDD = buildDDDModule( ... using AAA, BBB or CCC ... )
        val moduleEEE = module {
          single(createdAtStart = true) { ZZZ() }
        }
        val moduleFFF = module { ... }
        loadKoinModules(listOf(
          moduleDDD,
          moduleEEE,
          moduleFFF
        ))

The problem is that ZZZ does not get created when loadKoinModules is called. When ZZZ is something that we want to "fail fast", we won't know there is a problem until it gets instantiated later.

Describe the solution you'd like

The desired behavior is to have loadKoinModules() honor the createAtStart flag. The meaning of createAtStart would perfectly fit with the intent.

Describe alternatives you've considered

The current workaround is to place some dummy code that calls upon ZZZ early in the application.

@holgerbrandl
Copy link

The workaround does not apply when building a library, where ZZZ is usercode that is outside of the control of the library developer. Consider the following example

import org.koin.core.context.startKoin
import org.koin.dsl.module

class Core {
    init{ println("Init Core")}
}

class ZZZ {
    init{ println("Init ZZZ")}
}

fun main() {
    val coreModule = module { single(createdAtStart = true) { Core() } }


    val ka = startKoin { modules(coreModule) }

    // module definition is just inlined here for illustration, but would be provided by user when using the library built using koin
    val userModule = module { single(createdAtStart = true) { ZZZ() } }

    ka.koin.loadModules(listOf(userModule))

    println("finished setup")

    val foo = ka.koin.get<ZZZ>()
}

Because loadKoinModules() does not yet honor createAtStart, the initialization happens too late when the object is retrieved but not during setup. The output is

Init Core
finished setup
Init ZZZ

but the intent would be

Init Core
Init ZZZ
finished setup

Is there another workaround (like iterating all registered objects to force instantiation) until the bug is fixed?

@bseib
Copy link
Author

bseib commented Oct 5, 2020

Warning -- This hack/workaround is just a guess by just poking through the latest Koin code on github for a few minutes. I found a function createEagerInstances() that is responsible for carrying out the createdAtStart business. Assuming you have only a single scope, then the following would attempt to call that function again on the root scope.

loadKoinModules(listOf( ... ))
KoinContextHandler.get()._scopeRegistry.rootScope.createEagerInstances()

I have not actually tried this, nor do I know if there are any side effects of calling that function late in the game. So it's only a suggestion of where to poke while you look for a workaround.


I thought I might look at a proper solution and opening a PR, but after 20 minutes I couldn't get past having the right android stuff setup in my local environment to do a build. ☹️ So perhaps another time. 😃

@holgerbrandl
Copy link

Thanks @bseib for your help. However it currently does not work because createEagerInstances is tagged as internal, that is it can not be used outside of the koin codebase.

@arnaudgiuliani
Copy link
Member

added createEagerInstances parameter to loadModules function, in Koin 2.2.0

@iamriajul
Copy link

added createEagerInstances parameter to loadModules function, in Koin 2.2.0

Can you please give me an example for Android?

I'm trying this way, but it's an internal function
getKoin().createEagerInstances()

I have seen that KoinApplication has the createEagerInstances method as public, but I couldn't find a way to get the current KoinApplication instance!

Thanks.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants