-
-
Notifications
You must be signed in to change notification settings - Fork 229
feat: add @RecurringTask annotation #725
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
base: master
Are you sure you want to change the base?
Conversation
kagkarlsson
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Nice! Thank you for contributing such a useful feature! A few comments and questions, but looks good 👍
| for (int i = 0; i < method.getParameterTypes().length; i++) { | ||
| Class<?> parameterType = method.getParameterTypes()[i]; | ||
| if (!INPUT_ARGUMENTS_AVAILABLE_CLASSES.contains(parameterType) | ||
| && context.getBeanNamesForType(parameterType).length == 0) { | ||
| throw new IllegalArgumentException( | ||
| "RecurringTask annotated method is required to have specific inputs: TaskInstance, ExecutionContext or a Spring bean"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe possible to use for (Class<?> parameterType : method.getParameterTypes()) ... style loop?
Also, what do we gain by allowing inject of Spring beans via method-parameters? Isn't normal spring injection sufficient?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There are a lot of cases when a task depends on some class with the logic. If the injection is implemented on the input parameter level, then it is possible to pass dependencies to the method itself rather then injecting everything in the class.
The case with method injection:
@Configuration
public class ScheduledConfig {
void recurringSampleTask1(Service1 service1) {...}
void recurringSampleTask2(Service2 service2) {...}
void recurringSampleTask3(Service3 service3) {...}
}
The case with class injections that should work out of the box:
@Configuration
public class ScheduledConfig {
private final Service1 service1;
private final Service2 service2;
private final Service3 service3;
contructor {...}
void recurringSampleTask1() { use service1 }
void recurringSampleTask2() { use service2 }
void recurringSampleTask3() { use service3 }
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Feels a bit like re-implementing the Spring-injection, but not completely (for instance, what about Qualifiers?)
Are there examples of other projects doing this?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I checked Spring Scheduled and JobRunr, both don't have this feature.
Thank you for mentioning Qualifier, in this implementation it won't work, as other things like Lazy etc.
Agree, it is easier and less error-prone to leave injection to Spring. I'll remove it and fix the documentation and examples.
| String name(); | ||
|
|
||
| String cron() default "-"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Have you considered supporting the other inputs to Cron: zoneId and cronStyle?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I didn't think about this.
I see that there are 5 different CronStyles, I'll try to implement all of them.
CRON4J,
QUARTZ,
UNIX,
SPRING,
SPRING53;
And I think ZoneId should be added as a separate field in annotation.
| }) | ||
| .toArray(); | ||
| try { | ||
| ReflectionUtils.makeAccessible(method); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be better to require the method to be public?
| @RecurringTask(name = "taskFromAnnotation") | ||
| public void taskFromAnnotation() { | ||
| log.info("I'm a task from annotation"); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What is the schedule for this one? 🤔
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah I see the default:
String cron() default "-";Should we perhaps drop the default? User have to supply it..
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
On my day-to-day job my team uses this value as a way to disable jobs.
Maybe here it adds more confusion than it helps. I'll remove the default and make it required.
| @Bean | ||
| public RecurringTaskRegistryPostProcessor recurringTaskRegistryPostProcessor( | ||
| GenericApplicationContext context) { | ||
| return new RecurringTaskRegistryPostProcessor(context); | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Would it be possible to have the RecurringTaskRegistryPostProcessor resolve property-references in the cron-pattern?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea! I did a quick test and it's possible to make, needs some enhancements of RecurringTaskRegistryPostProcessor.
I'll add this to the PR.
…od as a parameter
| private Task<?> createTaskFromMethod( | ||
| RecurringTask recurringTask, Method method, Object existingObject, String resolvedCron) { | ||
|
|
||
| return Tasks.recurring(recurringTask.name(), Schedules.cron(resolvedCron)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I miss the option to configure the FailureHandler.
As far as I can see, the FailureHandler behavior cannot be configured. This means that the default Failure Handler is used automatically, which is not suitable for everyone.
I would be grateful if this functionality could be taken into account in this pull request.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Default is
this.onFailure = new FailureHandler.OnFailureReschedule<>(schedule);
Do you need a completely custom implementation? (I.e. lookup a FailureHandler in the app-context based on a bean-name?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes. I think that would be useful feature. You define your FailureHandlerBean. This FailureHandler will then be used for all the task, which are created via @RecurringTask annotation.
But this will not be enough for the case, where you have multiple @RecurringTask where each of them need an different FailureHandler.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I am also ok with adding customizable failure-handler in a future iteration of this.
This is a convenient short-hand for most common recurring tasks, and I don't think it needs to cover all variants
|
@kagkarlsson |
|
Yeah the |
Added the
@RecurringTaskannotation to simplify the creation of basic recurring tasks in a Spring environment.The main implementation is in the
RecurringTaskRegistryPostProcessorclass, which scans Spring beans for methods annotated with@RecurringTaskand registers a corresponding Task bean definition.The annotated method must follow these rules:
TaskInstanceandExecutionContextFixes
#509
Reminders
mvn spotless:applycc @kagkarlsson