InsertKoinIO / koin

Koin - a pragmatic lightweight dependency injection framework for Kotlin & Kotlin Multiplatform
https://insert-koin.io
Apache License 2.0
8.98k stars 710 forks source link

Since koin for ktor 3.5.0 install(Koin) doesnt work. Using startKoin works #1674

Closed patrickboisclair closed 10 months ago

patrickboisclair commented 11 months ago

I upgraded from koin 3.4.0 to 3.5.1 for Ktor and since then I get the error:

Exception in thread "DefaultDispatcher-worker-8" java.lang.IllegalStateException: KoinApplication has not been started at org.koin.core.context.GlobalContext.get(GlobalContext.kt:36) at org.koin.core.component.KoinComponent$DefaultImpls.getKoin(KoinComponent.kt:33) at com.noovelia.nooveliabeats.core.hostedservices.GrpcServer.getKoin(GrpcServer.kt:16) at com.noovelia.nooveliabeats.core.hostedservices.GrpcServer$special$$inlined$inject$default$1.invoke(KoinComponent.kt:68) at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) at com.noovelia.nooveliabeats.core.hostedservices.GrpcServer.getLoggingService(GrpcServer.kt:30) at com.noovelia.nooveliabeats.core.hostedservices.GrpcServer.access$getLoggingService(GrpcServer.kt:16) at com.noovelia.nooveliabeats.core.hostedservices.GrpcServer$run$1.invokeSuspend(GrpcServer.kt:35) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108) at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115) at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103) at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)

Instead of using: install(Koin), I tried with startKoin and it seems to work.

Koin module and version:

patrickboisclair commented 11 months ago

NOTE for reference, im using ktor 2.3.5

JerryPreissler commented 11 months ago

Just a note that I'm running into the same issue.

Also when moving from io.insert-koin:koin-ktor.3.4.3 to 3.5.0 tests like the following start to fail:

`@TestInstance(TestInstance.Lifecycle.PER_CLASS) class DokumentRestControllerTest : KoinTest {

@JvmField
@RegisterExtension
@Suppress("unused")
val koinTestExtension = KoinTestExtension.create {
    modules(
        restKoinModule,
        memoryPersistenceKoinTestModule,
    )
}

@Test
fun testGetDokumentUnknown() = testApplication {
    application {
        dokumentModule()
    }        // call with unknown id should result in 404
    client.get("/aktenordner/dokument/e58ed763-928c-4155-bee9-fdbaaadc15ff").apply {
        assertEquals(HttpStatusCode.NotFound, status)
    }
}

`

This works with 3.4.3, but with 3.5.0 I get java.lang.IllegalStateException: No instance for key AttributeKey: KOIN at io.ktor.util.Attributes$DefaultImpls.get(Attributes.kt:62) at io.ktor.util.AttributesJvmBase.get(AttributesJvm.kt:15) at org.koin.ktor.ext.ApplicationExtKt.getKoin(ApplicationExt.kt:34) at org.codeshards.aktenordner.adapter.incoming.rest.DokumentRestControllerKt$dokumentModule$$inlined$inject$default$1.invoke(ApplicationExt.kt:78) at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74) at org.codeshards.aktenordner.adapter.incoming.rest.DokumentRestControllerKt.dokumentModule$lambda$0(DokumentRestController.kt:29) at org.codeshards.aktenordner.adapter.incoming.rest.DokumentRestControllerKt.access$dokumentModule$lambda$0(DokumentRestController.kt:1) at org.codeshards.aktenordner.adapter.incoming.rest.DokumentRestControllerKt$dokumentModule$2$1$3.invokeSuspend(DokumentRestController.kt:43) at org.codeshards.aktenordner.adapter.incoming.rest.DokumentRestControllerKt$dokumentModule$2$1$3.invoke(DokumentRestController.kt) at org.codeshards.aktenordner.adapter.incoming.rest.DokumentRestControllerKt$dokumentModule$2$1$3.invoke(DokumentRestController.kt) at io.ktor.server.routing.Route$buildPipeline$1$1.invokeSuspend(Route.kt:116) at io.ktor.server.routing.Route$buildPipeline$1$1.invoke(Route.kt) at io.ktor.server.routing.Route$buildPipeline$1$1.invoke(Route.kt) at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:80) at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57) at io.ktor.util.pipeline.DebugPipelineContext.execute$ktor_utils(DebugPipelineContext.kt:63) at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77) at io.ktor.server.routing.Routing$executeResult$$inlined$execute$1.invokeSuspend(Pipeline.kt:478) at io.ktor.server.routing.Routing$executeResult$$inlined$execute$1.invoke(Pipeline.kt) at io.ktor.server.routing.Routing$executeResult$$inlined$execute$1.invoke(Pipeline.kt) at io.ktor.util.debug.ContextUtilsKt.initContextInDebugMode(ContextUtils.kt:17) at io.ktor.server.routing.Routing.executeResult(Routing.kt:190) at io.ktor.server.routing.Routing.interceptor(Routing.kt:64) at io.ktor.server.routing.Routing$Plugin$install$1.invokeSuspend(Routing.kt:140) at io.ktor.server.routing.Routing$Plugin$install$1.invoke(Routing.kt) at io.ktor.server.routing.Routing$Plugin$install$1.invoke(Routing.kt) at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:80) at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57) at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invokeSuspend(BaseApplicationEngine.kt:124) at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invoke(BaseApplicationEngine.kt) at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invoke(BaseApplicationEngine.kt) at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:80) at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57) at io.ktor.util.pipeline.DebugPipelineContext.execute$ktor_utils(DebugPipelineContext.kt:63) at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77) at io.ktor.server.testing.TestApplicationEngine$3$invokeSuspend$$inlined$execute$1.invokeSuspend(Pipeline.kt:478) at io.ktor.server.testing.TestApplicationEngine$3$invokeSuspend$$inlined$execute$1.invoke(Pipeline.kt) at io.ktor.server.testing.TestApplicationEngine$3$invokeSuspend$$inlined$execute$1.invoke(Pipeline.kt) at io.ktor.util.debug.ContextUtilsKt.initContextInDebugMode(ContextUtils.kt:17) at io.ktor.server.testing.TestApplicationEngine$3.invokeSuspend(TestApplicationEngine.kt:310) at io.ktor.server.testing.TestApplicationEngine$3.invoke(TestApplicationEngine.kt) at io.ktor.server.testing.TestApplicationEngine$3.invoke(TestApplicationEngine.kt) at io.ktor.server.testing.TestApplicationEngine$2.invokeSuspend(TestApplicationEngine.kt:90) at io.ktor.server.testing.TestApplicationEngine$2.invoke(TestApplicationEngine.kt) at io.ktor.server.testing.TestApplicationEngine$2.invoke(TestApplicationEngine.kt) at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:80) at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57) at io.ktor.util.pipeline.DebugPipelineContext.execute$ktor_utils(DebugPipelineContext.kt:63) at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77) at io.ktor.server.testing.TestApplicationEngine$handleRequestNonBlocking$2$invokeSuspend$$inlined$execute$1.invokeSuspend(Pipeline.kt:478) at io.ktor.server.testing.TestApplicationEngine$handleRequestNonBlocking$2$invokeSuspend$$inlined$execute$1.invoke(Pipeline.kt) at io.ktor.server.testing.TestApplicationEngine$handleRequestNonBlocking$2$invokeSuspend$$inlined$execute$1.invoke(Pipeline.kt) at io.ktor.util.debug.ContextUtilsKt.initContextInDebugMode(ContextUtils.kt:17) at io.ktor.server.testing.TestApplicationEngine$handleRequestNonBlocking$2.invokeSuspend(TestApplicationEngine.kt:309) at io.ktor.server.testing.TestApplicationEngine$handleRequestNonBlocking$2.invoke(TestApplicationEngine.kt) at io.ktor.server.testing.TestApplicationEngine$handleRequestNonBlocking$2.invoke(TestApplicationEngine.kt) at kotlinx.coroutines.intrinsics.UndispatchedKt.startUndispatchedOrReturn(Undispatched.kt:78) at kotlinx.coroutines.BuildersKt__Builders_commonKt.withContext(Builders.common.kt:167) at kotlinx.coroutines.BuildersKt.withContext(Unknown Source) at io.ktor.server.testing.TestApplicationEngine.handleRequestNonBlocking$ktor_server_test_host(TestApplicationEngine.kt:224) at io.ktor.server.testing.TestApplicationEngine.handleRequestNonBlocking$ktor_server_test_host$default(TestApplicationEngine.kt:211) at io.ktor.server.testing.client.TestHttpClientEngine.runRequest(TestHttpClientEngine.kt:70) at io.ktor.server.testing.client.TestHttpClientEngine.execute(TestHttpClientEngine.kt:55) at io.ktor.server.testing.client.DelegatingTestClientEngine.execute(DelegatingTestClientEngine.kt:55) at io.ktor.client.engine.HttpClientEngine$executeWithinCallContext$2.invokeSuspend(HttpClientEngine.kt:99) at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33) at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108) at kotlinx.coroutines.internal.LimitedDispatcher$Worker.run(LimitedDispatcher.kt:115) at kotlinx.coroutines.scheduling.TaskImpl.run(Tasks.kt:103) at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:584) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:793) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:697) at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:684)

GabrielLasso commented 11 months ago

Same here, downgraded to 3.4.3 and worked

tuncererdogan commented 11 months ago

Have you tried kotlin-bom to manage dependencies? I was having the same problem and found out that I was using koin-ktor v3.5.0 instead of v3.5.1 (together with koin-core-jvm:3.5.0). I think it has been introduced recently according to the changelog and this article.

patrickboisclair commented 11 months ago

@tuncererdogan Ty for the tips !

I tried providing the BOM, but it still gives me the same error.

19lmyers commented 11 months ago

I'm having the same issue, for what it's worth.

yashh commented 11 months ago

same problem here

JerryPreissler commented 11 months ago

Just a quick note that I've opened a separate issue for the problem with the failing tests after upgrading to 3.5.0

arnaudgiuliani commented 11 months ago

seems that isolated context feature is not working well. @patrickboisclair can you provide more details of the code that fail? is it running outside of Ktor?

I really need more details to help from anyone from this thread

JerryPreissler commented 11 months ago

@arnaudgiuliani , thanks for looking into this. I've uploaded a small sample project in the related issue that I mentioned above. In the version that is checked in I already applied the workaround for starting Koin but I can easily revert that. Then you should be able to recreate the problem with a simple gradle call. Would that help you?

arnaudgiuliani commented 11 months ago

yes 👍

JerryPreissler commented 11 months ago

@arnaudgiuliani I checked and the version I have pushed to Gitlab is already the one that exposes the problem. Here are the steps to reproduce: Change koin_ktor_version to 3.5.0 in gradle.properties

gradle clean
gradle build -x test
gradle run

Access http://localhost:8080/aktenordner/dokument from a browser or via curl.

You should see a stacktrace like this:

2023-10-31 18:29:15.798 [main] INFO  ktor.application - Responding at http://0.0.0.0:8080
2023-10-31 18:29:51.575 [eventLoopGroupProxy-4-2] INFO  [Koin] - | Scope 'q:'org.koin.ktor.plugin.RequestScope'' not defined. Creating it ...
2023-10-31 18:29:51.590 [eventLoopGroupProxy-4-2] ERROR ktor.application - Unhandled: GET - /aktenordner/dokument
java.lang.IllegalStateException: KoinApplication has not been started
        at org.koin.core.context.GlobalContext.get(GlobalContext.kt:36)
        at org.koin.core.component.KoinComponent$DefaultImpls.getKoin(KoinComponent.kt:33)
        at org.codeshards.aktenordner.application.service.ListDokumenteService.getKoin(ListDokumenteService.kt:10)
        at org.codeshards.aktenordner.application.service.ListDokumenteService$special$$inlined$inject$default$1.invoke(KoinComponent.kt:68)
        at kotlin.SynchronizedLazyImpl.getValue(LazyJVM.kt:74)
        at org.codeshards.aktenordner.application.service.ListDokumenteService.getListDokumentePort(ListDokumenteService.kt:12)
        at org.codeshards.aktenordner.application.service.ListDokumenteService.listDokumente(ListDokumenteService.kt:14)
        at org.codeshards.aktenordner.adapter.incoming.rest.DokumentRestControllerKt.handleListDokumente(DokumentRestController.kt:156)
        at org.codeshards.aktenordner.adapter.incoming.rest.DokumentRestControllerKt.access$handleListDokumente(DokumentRestController.kt:1)
        at org.codeshards.aktenordner.adapter.incoming.rest.DokumentRestControllerKt$dokumentModule$2$1$1.invokeSuspend(DokumentRestController.kt:37)
        at org.codeshards.aktenordner.adapter.incoming.rest.DokumentRestControllerKt$dokumentModule$2$1$1.invoke(DokumentRestController.kt)
        at org.codeshards.aktenordner.adapter.incoming.rest.DokumentRestControllerKt$dokumentModule$2$1$1.invoke(DokumentRestController.kt)
        at io.ktor.server.routing.Route$buildPipeline$1$1.invokeSuspend(Route.kt:116)
        at io.ktor.server.routing.Route$buildPipeline$1$1.invoke(Route.kt)
        at io.ktor.server.routing.Route$buildPipeline$1$1.invoke(Route.kt)
        at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:80)
        at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
        at io.ktor.util.pipeline.DebugPipelineContext.execute$ktor_utils(DebugPipelineContext.kt:63)
        at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
        at io.ktor.server.routing.Routing$executeResult$$inlined$execute$1.invokeSuspend(Pipeline.kt:478)
        at io.ktor.server.routing.Routing$executeResult$$inlined$execute$1.invoke(Pipeline.kt)
        at io.ktor.server.routing.Routing$executeResult$$inlined$execute$1.invoke(Pipeline.kt)
        at io.ktor.util.debug.ContextUtilsKt.initContextInDebugMode(ContextUtils.kt:17)
        at io.ktor.server.routing.Routing.executeResult(Routing.kt:190)
        at io.ktor.server.routing.Routing.interceptor(Routing.kt:64)
        at io.ktor.server.routing.Routing$Plugin$install$1.invokeSuspend(Routing.kt:140)
        at io.ktor.server.routing.Routing$Plugin$install$1.invoke(Routing.kt)
        at io.ktor.server.routing.Routing$Plugin$install$1.invoke(Routing.kt)
        at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:80)
        at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
        at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invokeSuspend(BaseApplicationEngine.kt:124)
        at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invoke(BaseApplicationEngine.kt)
        at io.ktor.server.engine.BaseApplicationEngineKt$installDefaultTransformationChecker$1.invoke(BaseApplicationEngine.kt)
        at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:80)
        at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
        at io.ktor.util.pipeline.DebugPipelineContext.execute$ktor_utils(DebugPipelineContext.kt:63)
        at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1$invokeSuspend$$inlined$execute$1.invokeSuspend(Pipeline.kt:478)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1$invokeSuspend$$inlined$execute$1.invoke(Pipeline.kt)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1$invokeSuspend$$inlined$execute$1.invoke(Pipeline.kt)
        at io.ktor.util.debug.ContextUtilsKt.initContextInDebugMode(ContextUtils.kt:17)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1.invokeSuspend(DefaultEnginePipeline.kt:123)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1.invoke(DefaultEnginePipeline.kt)
        at io.ktor.server.engine.DefaultEnginePipelineKt$defaultEnginePipeline$1.invoke(DefaultEnginePipeline.kt)
        at io.ktor.util.pipeline.DebugPipelineContext.proceedLoop(DebugPipelineContext.kt:80)
        at io.ktor.util.pipeline.DebugPipelineContext.proceed(DebugPipelineContext.kt:57)
        at io.ktor.util.pipeline.DebugPipelineContext.execute$ktor_utils(DebugPipelineContext.kt:63)
        at io.ktor.util.pipeline.Pipeline.execute(Pipeline.kt:77)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1$invokeSuspend$$inlined$execute$1.invokeSuspend(Pipeline.kt:478)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1$invokeSuspend$$inlined$execute$1.invoke(Pipeline.kt)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1$invokeSuspend$$inlined$execute$1.invoke(Pipeline.kt)
        at io.ktor.util.debug.ContextUtilsKt.initContextInDebugMode(ContextUtils.kt:17)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invokeSuspend(NettyApplicationCallHandler.kt:119)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
        at io.ktor.server.netty.NettyApplicationCallHandler$handleRequest$1.invoke(NettyApplicationCallHandler.kt)
        at kotlinx.coroutines.intrinsics.UndispatchedKt.startCoroutineUndispatched(Undispatched.kt:44)
        at kotlinx.coroutines.CoroutineStart.invoke(CoroutineStart.kt:112)
        at kotlinx.coroutines.AbstractCoroutine.start(AbstractCoroutine.kt:126)
        at kotlinx.coroutines.BuildersKt__Builders_commonKt.launch(Builders.common.kt:56)
        at kotlinx.coroutines.BuildersKt.launch(Unknown Source)
        at io.ktor.server.netty.NettyApplicationCallHandler.handleRequest(NettyApplicationCallHandler.kt:37)
        at io.ktor.server.netty.NettyApplicationCallHandler.channelRead(NettyApplicationCallHandler.kt:29)
        at io.netty.channel.AbstractChannelHandlerContext.invokeChannelRead(AbstractChannelHandlerContext.java:444)
        at io.netty.channel.AbstractChannelHandlerContext.access$600(AbstractChannelHandlerContext.java:61)
        at io.netty.channel.AbstractChannelHandlerContext$7.run(AbstractChannelHandlerContext.java:425)
        at io.netty.util.concurrent.AbstractEventExecutor.runTask(AbstractEventExecutor.java:174)
        at io.netty.util.concurrent.AbstractEventExecutor.safeExecute(AbstractEventExecutor.java:167)
        at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:470)
        at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:569)
        at io.netty.util.concurrent.SingleThreadEventExecutor$4.run(SingleThreadEventExecutor.java:997)
        at io.netty.util.internal.ThreadExecutorMap$2.run(ThreadExecutorMap.java:74)
        at io.ktor.server.netty.EventLoopGroupProxy$Companion.create$lambda$1$lambda$0(NettyApplicationEngine.kt:296)
        at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
        at java.base/java.lang.Thread.run(Thread.java:829)
JerryPreissler commented 11 months ago

If you want to see the version with the workaround ( startKoin instead of install(Koin) ) just switch the comment between the two versions of Application.module() in org/codeshards/Application.kt

tipapro commented 11 months ago

Same crash with this code for quartz job factory:

class DiJobFactory : JobFactory, KoinComponent {
    override fun newJob(
        bundle: TriggerFiredBundle?,
        scheduler: Scheduler?,
    ): Job {
        if (bundle != null) {
            val jobClass = bundle.jobDetail.jobClass

            return getKoin().get(jobClass.kotlin)
        }
        throw NotImplementedError("Job Factory error")
    }
}

Fixed it with GlobalContext.startKoin

install(Koin) {
    modules(modules)
    GlobalContext.startKoin(this)
 }

koin-bom 3.5.1

linnea-flexe commented 10 months ago

We encountered this issue ("KoinApplication has not been started") when updating a Ktor app to 3.5.1 (was 3.4.3). I cross referenced and we are accurately following the documentation and example code by using just install(Koin) { ... } and no explicit startKoin call.

This issue has been around for weeks - is there an ETA for a fix? Do we know which change causes the error?

arnaudgiuliani commented 10 months ago

I looking precisely how to revert the APi and keep the context isolation for Ktor. This is why I'm gathering feedbacks and samples. ETA for the fix is around 2 weeks max.

arnaudgiuliani commented 10 months ago

I reverted back the startKoin in the main Ktor plugin. I will publish a RC build to let you test 👍

arnaudgiuliani commented 10 months ago

Let's reopen it if someone sees a failure in RC release.

JerryPreissler commented 10 months ago

Just for the record: using 3.5.2-RC1 everything works fine for me. Sorry for the late feedback.