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

NoBeanDefFoundException in WorkManager #1729

Open
smuldr opened this issue Dec 6, 2023 · 6 comments
Open

NoBeanDefFoundException in WorkManager #1729

smuldr opened this issue Dec 6, 2023 · 6 comments

Comments

@smuldr
Copy link

smuldr commented Dec 6, 2023

Describe the bug
We get occasional crashes when using koin-androidx-workmanager to inject our worker classes. It seems like this is a continuation of #1623.

Fatal Exception: java.lang.Error: org.koin.core.error.InstanceCreationException: Could not create instance for '[Factory:'my.package.SomeWorker',qualifier:q:'my.package.SomeWorker',binds:androidx.work.ListenableWorker]'
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1173)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:920)
Caused by org.koin.core.error.InstanceCreationException: Could not create instance for '[Factory:'my.package.SomeWorker',qualifier:q:'my.package.SomeWorker',binds:androidx.work.ListenableWorker]'
       at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:57)
       at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
       at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:116)
       at org.koin.core.scope.Scope.resolveValue(Scope.kt:247)
       at org.koin.core.scope.Scope.resolveInstance(Scope.kt:233)
       at org.koin.core.scope.Scope.get(Scope.kt:212)
       at org.koin.core.scope.Scope.getOrNull(Scope.kt:177)
       at org.koin.core.scope.Scope.getOrNull$default(Scope.kt:160)
       at org.koin.androidx.workmanager.factory.KoinWorkerFactory.createWorker(KoinWorkerFactory.kt:41)
       at androidx.work.DelegatingWorkerFactory.createWorker(DelegatingWorkerFactory.java:71)
       at androidx.work.WorkerFactory.createWorkerWithDefaultFallback(WorkerFactory.java:83)
       at androidx.work.impl.WorkerWrapper.runWorker(WorkerWrapper.java:243)
       at androidx.work.impl.WorkerWrapper.run(WorkerWrapper.java:145)
       at androidx.work.impl.utils.SerialExecutorImpl$Task.run(SerialExecutorImpl.java:96)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:920)
Caused by org.koin.core.error.NoBeanDefFoundException: No definition found for type 'my.package.SomeWorker'. Check your Modules configuration and add missing type and/or qualifier!
       at org.koin.core.scope.Scope.throwDefinitionNotFound(Scope.kt:301)
       at org.koin.core.scope.Scope.resolveValue(Scope.kt:271)
       at org.koin.core.scope.Scope.resolveInstance(Scope.kt:233)
       at org.koin.core.scope.Scope.get(Scope.kt:212)
       at org.koin.core.scope.Scope.get$default(Scope.kt:136)
       at my.package.MyWorkerModuleKt$workersModule$1$11.invoke(MyWorkerModule.kt:51)
       at my.package.MyWorkerModuleKt$workersModule$1$11.invoke(MyWorkerModule.kt:47)
       at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:50)
       at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
       at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:116)
       at org.koin.core.scope.Scope.resolveValue(Scope.kt:247)
       at org.koin.core.scope.Scope.resolveInstance(Scope.kt:233)
       at org.koin.core.scope.Scope.get(Scope.kt:212)
       at org.koin.core.scope.Scope.getOrNull(Scope.kt:177)
       at org.koin.core.scope.Scope.getOrNull$default(Scope.kt:160)
       at org.koin.androidx.workmanager.factory.KoinWorkerFactory.createWorker(KoinWorkerFactory.kt:41)
       at androidx.work.DelegatingWorkerFactory.createWorker(DelegatingWorkerFactory.java:71)
       at androidx.work.WorkerFactory.createWorkerWithDefaultFallback(WorkerFactory.java:83)
       at androidx.work.impl.WorkerWrapper.runWorker(WorkerWrapper.java:243)
       at androidx.work.impl.WorkerWrapper.run(WorkerWrapper.java:145)
       at androidx.work.impl.utils.SerialExecutorImpl$Task.run(SerialExecutorImpl.java:96)
       at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
       at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
       at java.lang.Thread.run(Thread.java:920)

To Reproduce

Our flow is as follows:

  1. We removed the default WorkManager initializer from the AndroidManifest
  2. We use an Initializer from the AndroidX Startup component to start Koin and set up the Koin WorkManager factory.
  3. There is a second Initializer that enqueues a periodic WorkRequest in WorkManager. This worker initializer depends on our Koin initializer so Koin should be initialized.
  4. The app also enqueues some one time work when the first activity is created.

Both the periodic and the one time workers produce NoBeanDefFoundEception crashes. It only happens to a small percentage of users, but it still happens with every release we make.

Koin module and version:

  • Koin 3.5.1
  • AndroidX Startup 1.1.1
  • AndroidX WorkManager 2.8.1
@svob
Copy link

svob commented Jan 3, 2024

Hi, I have the same issue. Is there any solution or workaround for this?

@smuldr
Copy link
Author

smuldr commented Jan 3, 2024

We ended up removing the koin-androidx-workmanager library completely and made our workers KoinComponents so they can get or inject their dependencies when they actually do the work.

class MyWorker(
  appContext: Context,
  params: WorkerParameters,
) : Worker(appContext, params),
  KoinComponent {
  
  // Use `by inject()` to get a lazy dependency.
  private val myDependency: SomeClass by inject()

  override suspend fun doWork(): Result {
    // Only access the dependency in `doWork()`
    myDependency.doSomething()
    TODO("Return a result")
  }
}

This makes the class more difficult to test but at least the crashes went away. I guess that this approach gives Koin a little more time to get the dependency graph ready.

@arnaudgiuliani
Copy link
Member

Can you check how I setup it in NowInAndroid, and compare with yours? https://github.com/InsertKoinIO/nowinandroid

@smuldr
Copy link
Author

smuldr commented Jan 29, 2024

That is a big project to quickly check for the setup! 😄 Are you talking about the way you manually trigger the SyncWorker in the app's Application right here?

I am afraid that we have too much code relying on having Koin initialized via the AndroidX Startup library to quickly make this change. I should really put together a demo project to help figure out the cause of this crash rather than try to find a workaround.

@arnaudgiuliani
Copy link
Member

Seems that worker is not well defined. But it needs deeper investigation on your side 🤔

@ChrisKruegerDev
Copy link

Even in small workers and apps, this issue can happen:

@KoinWorker
class ScheduleRemindersWorker(
    context: Context,
    params: WorkerParameters,
    private val reminderRepository: RemindersRepository
) : TaskCoroutineWorker(context, params) {

    override suspend fun doTask() {
        reminderRepository.scheduleReminders()
    }
}

// execution
      workManager.enqueueUniqueWork(
            ScheduleRemindersWorker.NAME_STARTUP,
            ExistingWorkPolicy.KEEP,
            OneTimeWorkRequest.from(ScheduleRemindersWorker::class.java),
        )

Stack trace:

Fatal Exception: org.koin.core.error.InstanceCreationException: Could not create instance for '[Factory: 'app.resubs.data.reminder.ScheduleRemindersWorker',qualifier:app.resubs.data.reminder.ScheduleRemindersWorker,binds:androidx.work.c]'
      at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:58)
      at org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
      at org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:110)
      at org.koin.core.scope.Scope.resolveFromRegistry(Scope.kt:321)
      at org.koin.core.scope.Scope.resolveFromContext(Scope.kt:311)
      at org.koin.core.scope.Scope.stackParametersCall(Scope.kt:281)
      at org.koin.core.scope.Scope.resolveInstance(Scope.kt:259)
      at org.koin.core.scope.Scope.resolveWithOptionalLogging(Scope.kt:232)
      at org.koin.core.scope.Scope.get(Scope.kt:215)
      at org.koin.core.scope.Scope.getOrNull(Scope.kt:178)
      at org.koin.androidx.workmanager.factory.KoinWorkerFactory.createWorker(KoinWorkerFactory.kt:47)
      at androidx.work.DelegatingWorkerFactory.createWorker(DelegatingWorkerFactory.java:71)
      at androidx.work.WorkerFactory.createWorkerWithDefaultFallback(WorkerFactory.java)
      at androidx.work.impl.WorkerWrapper.runWorker(WorkerWrapper.java:243)
      at androidx.work.impl.WorkerWrapper.run(WorkerWrapper.java:144)
      at androidx.work.impl.utils.SerialExecutorImpl$Task.run(SerialExecutorImpl.java:96)
      at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
      at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:644)
      at java.lang.Thread.run(Thread.java:1012)

Questions to look into:

  • Does it work with obfuscation?
  • What happens if a worker is enqueued without WorkerParameters?

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