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

No definition found for class:'androidx.work.WorkerParameters' #1623

Closed
tyczj opened this issue Jul 19, 2023 · 24 comments
Closed

No definition found for class:'androidx.work.WorkerParameters' #1623

tyczj opened this issue Jul 19, 2023 · 24 comments
Labels
android:workmanager android status:checking currently in analysis - discussion or need more detailed specs type:issue
Milestone

Comments

@tyczj
Copy link

tyczj commented Jul 19, 2023

Describe the bug
Using 3.4.2 of koin work manager I am getting this error sometimes when trying to start a work manager instance

* Instance creation error : could not create instance for '[Factory:'x.x.x.x.workers.DailyMaintenanceWorker',qualifier:q:'x.x.x.x.workers.DailyMaintenanceWorker',binds:androidx.work.ListenableWorker]': org.koin.core.error.NoBeanDefFoundException: No definition found for class:'androidx.work.WorkerParameters' q:''. Check your definitions!
  org.koin.core.scope.Scope.throwDefinitionNotFound(Scope.kt:304)
  org.koin.core.scope.Scope.resolveValue(Scope.kt:274)
  org.koin.core.scope.Scope.resolveInstance(Scope.kt:231)
  org.koin.core.scope.Scope.get(Scope.kt:210)
  x.x.x.x.AppBase$baseModule$1$invoke$$inlined$workerOf$default$7.invoke(WorkerOf.kt:221)
  x.x.x.x.AppBase$baseModule$1$invoke$$inlined$workerOf$default$7.invoke(WorkerOf.kt:94)
  org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:51)
  org.koin.core.instance.FactoryInstanceFactory.get(FactoryInstanceFactory.kt:38)
  org.koin.core.registry.InstanceRegistry.resolveInstance$koin_core(InstanceRegistry.kt:116)
  org.koin.core.scope.Scope.resolveValue(Scope.kt:246)
  org.koin.core.scope.Scope.resolveInstance(Scope.kt:231)
  org.koin.core.scope.Scope.get(Scope.kt:210)
  org.koin.core.scope.Scope.getOrNull(Scope.kt:175)
  org.koin.androidx.workmanager.factory.KoinWorkerFactory.createWorker(KoinWorkerFactory.kt:47)
  androidx.work.DelegatingWorkerFactory.createWorker(DelegatingWorkerFactory.java:71)
  androidx.work.WorkerFactory.createWorkerWithDefaultFallback(WorkerFactory.java:83)
  androidx.work.impl.WorkerWrapper.runWorker(WorkerWrapper.java:243)
  androidx.work.impl.WorkerWrapper.run(WorkerWrapper.java:145)
  androidx.work.impl.utils.SerialExecutorImpl$Task.run(SerialExecutorImpl.java:96)
  java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1167)
  java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:641)
  java.lang.Thread.run(Thread.java:923)
E  Unable to instantiate a ListenableWorker (x.x.x.x.workers.DailyMaintenanceWorker)
  org.koin.core.error.InstanceCreationException: Could not create instance for '[Factory:'x.x.x.x.workers.DailyMaintenanceWorker',qualifier:q:'x.x.x.x.workers.DailyMaintenanceWorker',binds:androidx.work.ListenableWorker]'
  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:116)
  at org.koin.core.scope.Scope.resolveValue(Scope.kt:246)
  at org.koin.core.scope.Scope.resolveInstance(Scope.kt:231)
  at org.koin.core.scope.Scope.get(Scope.kt:210)
  at org.koin.core.scope.Scope.getOrNull(Scope.kt:175)
  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: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:923)
Caused by: org.koin.core.error.NoBeanDefFoundException: No definition found for class:'androidx.work.WorkerParameters' q:''. Check your definitions!
  at org.koin.core.scope.Scope.throwDefinitionNotFound(Scope.kt:304)
  at org.koin.core.scope.Scope.resolveValue(Scope.kt:274)
  at org.koin.core.scope.Scope.resolveInstance(Scope.kt:231)
  at org.koin.core.scope.Scope.get(Scope.kt:210)
  at x.x.x.x.AppBase$baseModule$1$invoke$$inlined$workerOf$default$7.invoke(WorkerOf.kt:221)
  at x.x.x.x.AppBase$baseModule$1$invoke$$inlined$workerOf$default$7.invoke(WorkerOf.kt:94)
  at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:51)
  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:246) 
  at org.koin.core.scope.Scope.resolveInstance(Scope.kt:231) 
  at org.koin.core.scope.Scope.get(Scope.kt:210) 
  at org.koin.core.scope.Scope.getOrNull(Scope.kt:175) 
  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: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:923) 
E  FATAL EXCEPTION: WM.task-3
  Process: x.x.x.x, PID: 1500
  java.lang.Error: org.koin.core.error.InstanceCreationException: Could not create instance for '[Factory:'x.x.x.x.workers.DailyMaintenanceWorker',qualifier:q:'x.x.x.x.workers.DailyMaintenanceWorker',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:923)
Caused by: org.koin.core.error.InstanceCreationException: Could not create instance for '[Factory:'x.x.x.x.workers.DailyMaintenanceWorker',qualifier:q:'x.x.x.x.workers.DailyMaintenanceWorker',binds:androidx.work.ListenableWorker]'
  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:116)
  at org.koin.core.scope.Scope.resolveValue(Scope.kt:246)
  at org.koin.core.scope.Scope.resolveInstance(Scope.kt:231)
  at org.koin.core.scope.Scope.get(Scope.kt:210)
  at org.koin.core.scope.Scope.getOrNull(Scope.kt:175)
  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: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:923) 
Caused by: org.koin.core.error.NoBeanDefFoundException: No definition found for class:'androidx.work.WorkerParameters' q:''. Check your definitions!
  at org.koin.core.scope.Scope.throwDefinitionNotFound(Scope.kt:304)
  at org.koin.core.scope.Scope.resolveValue(Scope.kt:274)
  at org.koin.core.scope.Scope.resolveInstance(Scope.kt:231)
  at org.koin.core.scope.Scope.get(Scope.kt:210)
  at x.x.x.x.AppBase$baseModule$1$invoke$$inlined$workerOf$default$7.invoke(WorkerOf.kt:221)
  at x.x.x.x.AppBase$baseModule$1$invoke$$inlined$workerOf$default$7.invoke(WorkerOf.kt:94)
  at org.koin.core.instance.InstanceFactory.create(InstanceFactory.kt:51)
  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:246) 
  at org.koin.core.scope.Scope.resolveInstance(Scope.kt:231) 
  at org.koin.core.scope.Scope.get(Scope.kt:210) 
  at org.koin.core.scope.Scope.getOrNull(Scope.kt:175) 
  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: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:923) 

The definition of work manager in my application class is just this

workerOf(::DailyMaintenanceWorker)

This happens on a TCL Google TV device, Model# 32S356

I also have another Google TV from Sony and does not seem to happen though so it might be device dependent?

Can provide more information if needed

To Reproduce
Steps to reproduce the behavior:
Create a worker
Try to start worker upon app startup

Expected behavior
Worker launches without error

Koin project used and used version (please complete the following information):
koin work manager 3.4.2
koin core 3.4.2

Additional moduleDefinition

Work manager version 2.8.1

@tyczj
Copy link
Author

tyczj commented Jul 19, 2023

in koin version 3.4.0 it still cannot create the worker but it does not fully crash the app like it does in 3.4.2.

I get this error

E  Could not instantiate x.x.x.x.workers.IntervalWorker
java.lang.NoSuchMethodException: x.x.x.x.workers.IntervalWorker.<init> [class android.content.Context, class androidx.work.WorkerParameters]
at java.lang.Class.getConstructor0(Class.java:2332)
at java.lang.Class.getDeclaredConstructor(Class.java:2170)
at androidx.work.WorkerFactory.createWorkerWithDefaultFallback(WorkerFactory.java:95)
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:923)
E  Could not create Worker x.x.x.x.workers.IntervalWorker                    java.lang.NoSuchMethodException: x.x.x.x.workers.IntervalWorker.<init> [class android.content.Context, class androidx.work.WorkerParameters]
at java.lang.Class.getConstructor0(Class.java:2332)
at java.lang.Class.getDeclaredConstructor(Class.java:2170)
at androidx.work.WorkerFactory.createWorkerWithDefaultFallback(WorkerFactory.java:95)
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:923)

@tyczj
Copy link
Author

tyczj commented Jul 21, 2023

Looks like it's something similar to this issue because as one of the comments states, if I do

workerOf(::DailyMaintenanceWorker) { named<DailyMaintenanceWorker>() }

everything seems to work fine again

@Nek-12
Copy link

Nek-12 commented Jul 31, 2023

That issue was not fully fixed. I have the same issue - it occurs rarely, which leads me to believe there is a race there.

@lucianocn
Copy link

I can confirm that the issue persists with Koin Work Manager 3.4.3 and Core 3.4.3 using workerOf.

@tyczj
Copy link
Author

tyczj commented Aug 4, 2023

Even with

worker(named<DailyMaintenanceWorker>()) { DailyMaintenanceWorker(get())}

it still happens so not limited to workerOf

@arnaudgiuliani
Copy link
Member

anyone can help reproduce?

@arnaudgiuliani arnaudgiuliani added android type:issue android:workmanager status:checking currently in analysis - discussion or need more detailed specs labels Aug 4, 2023
@arnaudgiuliani arnaudgiuliani added this to the android-3.5.0 milestone Aug 4, 2023
@tyczj
Copy link
Author

tyczj commented Aug 4, 2023

I am only able to reproduce it on the device I specified in my OP, but in my app I have multiple work managers and the one that runs every 15 min (the minimum time available to run a work manager task) is the one I see it the most on. It can take a couple of days of constant running for it to happen at which time the app will crash. Trying to launch the app again (which starts the work manager as a one time task initially) it will crash. let the device sit for a bit and I can run the app again

If it matters any I inject via constructor of the workmanager

class IntervalWorker (private val fileUtil: FileUtil, private val scheduleService: ScheduleService, context: Context, parameters: WorkerParameters) :
    BaseWorker(context, parameters) {

}

Where BaseWorker is a class that all my workers implement

open class BaseWorker (val context: Context, val parameters: WorkerParameters) :
    CoroutineWorker(context, parameters) {

    open fun createForegroundInfo(channelId: String, channelName: String, notificationId: Int, serviceType: Int): ForegroundInfo {

    }

    override suspend fun doWork(): Result {
        return Result.success()
    }
}

@arnaudgiuliani
Copy link
Member

the othe thing to test, is to not use constructor injection but by inject to bypass the constructor injection of workerOf. Just to be sure, we know from where it comes.

@tyczj
Copy link
Author

tyczj commented Aug 4, 2023

does that mean I need use KoinComponent on the work manager to be able to use by inject?

@arnaudgiuliani
Copy link
Member

yes, to check the current context

@lucianocn
Copy link

lucianocn commented Aug 4, 2023

Hi @arnaudgiuliani,

I have been unable to replicate this error in debug mode. It seems to manifest exclusively on production devices and occurs very rarely. Our app is being utilized by ~200 devices and the error occurs ~3 times daily.

After reviewing our release history, it can be related to the changes involving single and worker to singleOf and workerOf.

RepositoriesModule.kt

val repositoriesModule = module {
    singleOf(::SyncRepository) // 14 injections.
}

WorkersModule.kt

val workersModule = module {
    workerOf(::SyncWorker)
}

MyApplication.kt

class MyApplication : Application(), KoinComponent {

    override fun onCreate() {
        super.onCreate()

        // Koin
        startKoin {
            androidContext(this@MyApplication)
            workManagerFactory()
            modules(appModule) // Injects RepositoriesModule and WorkersModule
        }

        // SyncWorker - Periodic (15 minutes)
        syncWorkerPeriodic()
    }


    private fun syncWorkerPeriodic() {
        val constraintsBuilder: Constraints.Builder = Constraints.Builder()
            .setRequiredNetworkType(NetworkType.CONNECTED)

        val periodicWorkRequest = PeriodicWorkRequestBuilder<SyncWorker>(15, TimeUnit.MINUTES)
            .setConstraints(constraintsBuilder.build())
            .build()

        WorkManager.getInstance(applicationContext)
            .enqueueUniquePeriodicWork("syncWorkerPeriodic", ExistingPeriodicWorkPolicy.KEEP, periodicWorkRequest)
    }
}

SyncWorker.kt

class SyncWorker(
    context: Context,
    params: WorkerParameters,
    private val syncRepository: SyncRepository
) : CoroutineWorker(context, params), KoinComponent {
    @OptIn(SyncRepository.SyncDelicateMethod::class)
    override suspend fun doWork(): Result {
        val showFeedback = inputData.getBoolean("showFeedback", false)
        syncRepository.execWorker(showFeedback)
        return Result.success()
    }
}

Error
org.koin.core.error.InstanceCreationException: Could not create instance for '[Factory:'com.app.android.modules.core.workers.SyncWorker',qualifier:q:'com.app.android.modules.core.workers.SyncWorker',binds:androidx.work.ListenableWorker]'

InstanceCreationException
Could not create instance for '[Factory:'com.app.android.modules.core.workers.SyncWorker',qualifier:q:'com.app.android.modules.core.workers.SyncWorker',binds:androidx.work.ListenableWorker]'

Sentry Log: https://dpen.sentry.io/share/issue/212a63cf0f4d4e9e9ccc7237156a274a/

@lucianocn
Copy link

Yesterday I released a new app version with the code mentioned above. No error has surfaced yet, but it might be a coincidence due to limited testing. I'll keep an eye on it and provide updates here.

val workersModule = module {
    workerOf(::SyncWorker) { named<SyncWorker>() }
}

@Mardaneus86
Copy link

Issue occurs here as well, but not reproducible in debug since it occurs very rarely. This will only be noticeable when the install-base is high enough. Currently about 13 users of the 2900 seem to be affected (about 0,5%).

We need to inject some custom dependencies in the worker, and don't want to add a Koin dependency in the Workers themselves because we want to keep the Workers DI-agnostic. That's why we're using the following format for initialisation in the Koin module, as an example:

worker(named<BackgroundWorker>()) {
    BackgroundWorker(
        context = androidContext(),
        params = get(),
        repository = get(),
        dispatcher = get(named(IO_DISPATCHER))
    )
}

I'm guessing @lucianocn's approach with the workerOf(...) { named<...>() } is not usable in that case?

@tyczj
Copy link
Author

tyczj commented Aug 7, 2023

I let it run over the weekend with without using constructor injection and using KoinComponent; didnt have any issues and it would have most likely have happened during that time.

Does that also mean I could remove all usages of workerOf when using KoinComponent?

@lucianocn
Copy link

lucianocn commented Aug 7, 2023

The following code didn't resolve the problem 😵‍💫

val workersModule = module {
    workerOf(::SyncWorker) { named<SyncWorker>() }
}

@Mardaneus86
Copy link

We've released our app with the KoinComponent approach in the Workers and that resolves it, as a workaround. We are in this case no longer using the worker or workerOf methods, and thus also not the Koin-based Worker factory anymore.

@Brock-Gibson
Copy link

@Mardaneus86 Facing the same problem at the moment. For your use of KoinComponent, were you using the default worker factory and injecting everything in the class itself or using a DelegatingWorkerFactory and injecting the dependencies into the class constructors there?

@lucianocn
Copy link

lucianocn commented Aug 12, 2023

@Brock-Gibson

  1. Remove koin-androidx-workmanager dependency and revert implementations (https://insert-koin.io/docs/reference/koin-android/workmanager/).
  2. Add androidx.work:work-runtime-ktx dependency (https://developer.android.com/jetpack/androidx/releases/work).
  3. Implement worker with KoinComponent and by inject, like:
class YourWorker(context: Context,params: WorkerParameters) : CoroutineWorker(context, params), KoinComponent {
    private val repository: Repository by inject() // <--
    override suspend fun doWork(): Result {
        // ...
    }
}

@gerbiljames
Copy link

This is being caused by parameter resolution not being threadsafe, and is fixed by this PR. It's more likely to happen when multiple workers are triggered at the same time, which is often the case on production devices when JobScheduler wakes up apps to do batched work.

It doesn't happen when using KoinComponent since that doesn't use Koin to construct the worker, which means it never has to resolve the WorkerParameters.

@arnaudgiuliani
Copy link
Member

do you think it's the case of parameter resolution for each worker? kindof race condition/thread safety problem.

@gerbiljames
Copy link

do you think it's the case of parameter resolution for each worker? kindof race condition/thread safety problem.

I do, WorkManager manages a thread pool on which it creates workers, when enough workers are created at the same time there's a small chance that some are created on different threads in this pool which may trigger this bug.

@arnaudgiuliani
Copy link
Member

arnaudgiuliani commented Sep 4, 2023

closing this, let's reopen after 3.5.0 version update if needed 👍

PR #1643 is merging

@smuldr
Copy link

smuldr commented Dec 4, 2023

We are still seeing this issue with Koin 3.5.1. It only happens to a small percentage of users, but it still happens reliably.

Our flow is as follows:

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

Both workers from step 3 and 4 produce NoBeanDefFoundEception crashes.

Android 33
Koin 3.5.1
AndroidX Startup 1.1.1

@arnaudgiuliani
Copy link
Member

@smuldr can you reopen a new issue?

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

No branches or pull requests

8 participants