Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Spring Boot @EnableScheduling conditionally

Is there a way to make @EnableScheduling conditional based on an application property? also is it possible to disable controllers based on properties too?

What I'm trying to achieve is to have the same spring boot application used to serve web requests (but not run scheduled tasks on the same machine), and also install the same app on backend servers to run only scheduled tasks.

My app looks like this

@SpringBootApplication
@EnableScheduling
@EnableTransactionManagement
public class MyApp {

   public static void main(String[] args) {
        SpringApplication.run(MyApp.class, args);
   }

}

And a sample scheduled job looks like this

@Component
public class MyTask {

   @Scheduled(fixedRate = 60000)
   public void doSomeBackendJob() {
       /* job implementation here */
   }
}
like image 998
Badr Ghatasheh Avatar asked Aug 27 '16 15:08

Badr Ghatasheh


4 Answers

I Solved this, here is what I did for future reference:

  • Removed @EnableScheduling annotation from my app
  • Added a new configuration class and conditional to enable/disable scheduling based on an application property

-

 @Configuration
 public class Scheduler {

    @Conditional(SchedulerCondition.class)
    @Bean(name = TaskManagementConfigUtils.SCHEDULED_ANNOTATION_PROCESSOR_BEAN_NAME)
    @Role(BeanDefinition.ROLE_INFRASTRUCTURE)
    public ScheduledAnnotationBeanPostProcessor scheduledAnnotationProcessor() {
        return new ScheduledAnnotationBeanPostProcessor();
    }
}

And the conditional class

public class SchedulerCondition implements Condition {
    @Override
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        return Boolean.valueOf(context.getEnvironment().getProperty("com.myapp.config.scheduler.enabled"));
    }

}

Also, to disable web server on the backend server, just add the following to the application.properties file:

spring.main.web_environment=false
like image 174
Badr Ghatasheh Avatar answered Nov 09 '22 16:11

Badr Ghatasheh


I ended up creating a separate @Configuration class for scheduling and used the @ConditionalOnProperty annotation to toggle scheduling

@Configuration
@EnableScheduling
@ConditionalOnProperty(prefix = "scheduling", name="enabled", havingValue="true", matchIfMissing = true)
public class SchedulerConfig {

}

in my application.yml file I then added

scheduling:
  enabled: true
like image 44
ashario Avatar answered Nov 09 '22 16:11

ashario


You can annotate a bean injection like this:

@Bean
@ConditionalOnProperty(prefix = "your.property", name = "yes", matchIfMissing = true)
public void doSomeBackendJob() {
       /* job implementation here */
}

Bonus: Since you want to run different things in different machines, i.e., you will deploy the same app with different configurations, you could use spring profiles, if that's the case you can annotate a class or method like this:

@Component
@Profile({ Constants.SPRING_PROFILE_PRODUCTION, Constants.SPRING_PROFILE_TEST })
public class TheClass{...}
like image 8
imTachu Avatar answered Nov 09 '22 18:11

imTachu


  1. I think scheduler is not configuration.
  2. No need to set prefix in @ConditionalOnProperty
  3. No need to create scheduler over @Bean in configuration class.

My variant:

@Component
@EnableScheduling
@ConditionalOnProperty(value = "scheduler.enabled", havingValue = "true")
public class MyScheduler {

    @Scheduled(...)
    public void doWork() {
        ...
    }
}

like image 2
acidelk Avatar answered Nov 09 '22 18:11

acidelk