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

java.lang.IllegalStateException: Deque is too big #1353

Closed
shettigarsanthosh opened this issue May 26, 2022 · 16 comments
Closed

java.lang.IllegalStateException: Deque is too big #1353

shettigarsanthosh opened this issue May 26, 2022 · 16 comments
Assignees
Labels
core important 🔥 status:checking currently in analysis - discussion or need more detailed specs
Milestone

Comments

@shettigarsanthosh
Copy link

shettigarsanthosh commented May 26, 2022

Facing following issue, when tried to use access get() in KoinComponent Scope

java.lang.IllegalStateException: Deque is too big.
at kotlin.collections.ArrayDeque.ensureCapacity(ArrayDeque.java:59)
at kotlin.collections.ArrayDeque.addFirst(ArrayDeque.java:124)
at org.koin.core.scope.Scope.resolveInstance(Scope.java:238)
at org.koin.core.scope.Scope.get(Scope.java:204)

Can you please help to understand the possible root cause for above crash ?
Koin version - 3.1.5

@stuebingerb
Copy link

stuebingerb commented Jun 10, 2022

I would like to jump in here as we have been experiencing the same exception with Koin 3.1.6 and now with Koin 3.2.0 with a purely Kotlin/Ktor/Koin based backend service running in multiple instances on k8s.

The issue seems to be that the _parameterStack is filling up. I am not suggesting that there is a bug in Koin but we have a rather complex Koin setup and would also be happy to get some starting points for further investigation. We can also see that not all of our pods are affected equally, so there seem to be some yet-to-be-found special circumstances. We haven't been able to reproduce the issue locally yet.

If it helps, we have created a metric to observe the _parameterStack.size for the root scope (which is our only scope).

General overview over 2 days, with each line representing one of our pods, showing sizes of up to 17.000 elements:
image

And a single failing pod, showing the size going down to -2, presumably due to integer overflow:
image

@shettigarsanthosh
Copy link
Author

Any update root cause for this issue ?

@arnaudgiuliani arnaudgiuliani added core important 🔥 status:checking currently in analysis - discussion or need more detailed specs labels Jun 27, 2022
@arnaudgiuliani arnaudgiuliani added this to the 3.2.1 milestone Jun 27, 2022
@arnaudgiuliani
Copy link
Member

Clearly need investigation yes 👍

@stuebingerb
Copy link

Can we do anything to support?

@arnaudgiuliani
Copy link
Member

if you have any sample app that help reproduce, it's a great help.

@stuebingerb
Copy link

stuebingerb commented Jul 22, 2022

As of now I don't have any sample code that I would be allowed to share unfortunately.

But I may have a lead: We have classes implementing KoinComponent which we are not injecting via Koin but instead manually instantiate via their constructor - within the context of a Koin managed class. Simplified:

module {
    single { Service() }
}
class HelperB : KoinComponent {
    fun bar() { /* Implementation */ }
}
class HelperA : KoinComponent {
    fun foo() {
        HelperB().bar()
    }
}
class Service : KoinComponent {
    fun process() {
        HelperA().foo()
    }
}
class Wrapper : KoinComponent {
    get<Service>.process()
}

And when I look at the parameterStack at sizes > 0 I can see ParametersHolder instances (only) for HelperA and HelperB (along with some null entries).

Now when I add HelperA to the module definition and replace the instance creation with get<HelperA>() it disappears from the parameter stack and only instances for HelperB remain:

module {
    single { Service() }
    single { HelperA() }
}
class HelperB : KoinComponent {
    fun bar() { /* Implementation with logger injected by Koin */ }
}
class HelperA : KoinComponent {
    fun foo() {
        HelperB().bar()
    }
}
class Service : KoinComponent {
    fun process() {
        get<HelperA>().foo()
    }
}
class Wrapper : KoinComponent {
    get<Service>.process()
}

I still don't quite understand why the same code seems to behave so differently in different pods (and why the parameter size still goes down sometimes, or why it seems to have appeared only more or less recently) but to me this looks like a very potential root cause candidate (and incorrect use of Koin, thus qualifying indeed as "not a bug").

Does any of that sound plausible?

@stuebingerb
Copy link

I think I can confirm that the above change (getting rid of manual instance creation within a Koin managed context) fixed the issue for us. Maybe @shettigarsanthosh can confirm for them, otherwise I'd leave it up to you how to proceed here.

@Ferum-bot
Copy link

Ferum-bot commented Aug 11, 2022

Have the same issue 🧐

@arnaudgiuliani arnaudgiuliani modified the milestones: 3.2.1, 3.3.0 Aug 29, 2022
@PenzK
Copy link

PenzK commented Oct 12, 2022

Also faced such issue after migrating to 3.2.1 from 2.1.5

We use dynamic resolving by named argument
We have content provider which receives commands with name, on receiving command koin resolve by a named argument and some params
getKoin().getOrNull<IContentProviderDelegate>(named(contentType.name)) { parametersOf(params ?: "") }

on other end we have

factory<IContentProviderDelegate>(named(ContentType.name)) { (request: String) -> SomeProviderDelegate( jsonRequest = request, someStaff = get(), ... ) }

For now assuming that due to concurrent calls to content provider arraydeque params logic has some issues

In some cases we got ArrayDeque is empty , in some ArrayDeque is too big

@partho-mt
Copy link

I'm facing this issue while using inject as well. My code is as follows:
val service: Service = injectByComponent { parametersOf(param) }

And my injectByComponent method is:

inline fun <reified T> injectByComponent(
    noinline parameters: ParametersDefinition? = null
): T {
    return object : KoinComponent {
        val value: T by inject(parameters = parameters)
    }.value
}

Koin version: 3.2.2

@arnaudgiuliani arnaudgiuliani self-assigned this Oct 26, 2022
@poldz123
Copy link

Any update for this issue? as we are having the same crash as well

@arnaudgiuliani
Copy link
Member

are you all using it in ktor?

@partho-mt
Copy link

@arnaudgiuliani I am.

@PenzK
Copy link

PenzK commented Nov 2, 2022

are you all using it in ktor?

We aren't

@arnaudgiuliani
Copy link
Member

I believe we can try this fix: b2efb22

this is pushing synchronization when we have parameters on stack. This would avoid having dangling parameters on stack

I will publish it in Koin 3.3.

@arnaudgiuliani
Copy link
Member

Feel free to reopen an issue if you need 👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
core important 🔥 status:checking currently in analysis - discussion or need more detailed specs
Projects
None yet
Development

No branches or pull requests

7 participants