micronaut-projects / micronaut-core

Micronaut Application Framework
http://micronaut.io
Apache License 2.0
6.01k stars 1.05k forks source link

@Scheduled does not work with expressions in cron value #10529

Open hrothwell opened 5 months ago

hrothwell commented 5 months ago

Expected Behavior

When making a @Scheduled function, I should ideally be able to use Micronaut's expression language in combination with this to populate the cron expression - #{this.cron}

Use case: creating a base scheduled task that may perform the same logic across multiple instances, each singleton instance has its own cron loaded from property sources

Actual Behaviour

When trying to do so, the app will compile but fails at runtime:

ERROR i.m.context.DefaultBeanContext - Error processing bean method Definition: com.github.hrothwell.NoAbstractInvolved.void scheduledRun() with processor (io.micronaut.scheduling.processor.ScheduledMethodProcessor@6616b0a7): Can not evaluate expression [#{this.cron}]. Current resolve 'this' within expression context. Expressions that resolve 'this' should be executed in a non-static context.
io.micronaut.context.exceptions.ExpressionEvaluationException: Can not evaluate expression [#{this.cron}]. Current resolve 'this' within expression context. Expressions that resolve 'this' should be executed in a non-static context.

Seems to also occur in other fields such as fixedDelay

If the field being used is private instead a compilation error occurs: Failed to compile evaluated expression [#{this.cron}]. Cause: Can not find property with name [cron] in class com.github.hrothwerll.NoAbstractInvolved

Steps To Reproduce

  1. Create a scheduled job
  2. in the cron field attempt to use expression language combined with this

Environment Information

No response

Example Application

https://github.com/hrothwell/micronaut-demo/tree/scheduled-expression-language

Version

4.3.6+

graemerocher commented 5 months ago

so currently the cron expression is retrieved before the job instance is created so there is no way to refer to this. You could create a global custom expression context to referred to another bean though.

hrothwell commented 5 months ago

@graemerocher with the intent being to have one annotated method in an abstract class and all classes possibly having a different cron schedule in the annotation, so I'm not sure that that would quite work 🤔 If we referred to another bean, we'd probably still need to pass something like what the class name is in that case which I would assume would also reference this (something like this.javaClass.simpleName). Not a big deal either way, just thought I'd reach out and see if I was doing something wrong, bug, or just not feasible for the time being.

graemerocher commented 4 months ago

I think the only way to solve this would be to eagerly initialise beans with @Scheduled with expressions. Since it is a chicken and egg problem. Currently code doesn't create the instance until the job is actually run but a cron expression that references this needs to create the instance to compute the schedule.