Issue
I am working on a springboot project which have REST APIs and some scheduled task(@Scheduled
). Currently we have two server and I want to deploy same code in both server. So, my requirement is, One server should serve only API requests and other server should run only cron job.
How to restrict first server to run cron job.
One solution I can think of mark scheduler class with @Profile("{spring.profiles.active}")
and deploy with cron profiles..but I will have to add additional 4 set of profile in application.properties. like cron.prod, cron.dev, cron.qa, cron.stage. So total will be 8 set of profile.
I am pasting my existing code here. in application.properties
myservice.lmsurl=${${spring.profiles.active}.myservice.lmsurl}
prod.myservice.lmsurl=https://test.com
qa.myservice.lmsurl=https://test.com
dev.myservice.lmsurl=https://test.com
uat.myservice.lmsurl=https://test.com
in Appconfiguration.class
@Configuration
@ConfigurationProperties("myservice")
public class AppConfiguration {
@NotEmpty
private String lmsurl;
}
Any other better solution.
Solution
You would need only "cron" profile. For the different environment (DEV, QA, ..), you will need to externalize the value of the properties.
By example myservice.lmsurl=${myservice.lmsurl}
And then Spring will cascade to find the value https://docs.spring.io/spring-boot/docs/2.1.9.RELEASE/reference/html/boot-features-external-config.html
By example, if you deploy in a Tomcat, you can set the value in an xml file. If you deploy in AWS, you can set it as environment variable, ...
And off course you will have to set also in this externalized configuration the profile you want to use: spring.profiles.active to tell if you want to use cron or not.
Example for CRON
Your scheduler:
@Component
@Profile("cron")
public class CronScheduler {
@Scheduled(fixedDelay = 43200000)
public void job1() {
// some code
}
}
This class will be loaded only if the profile is active. In your application.properties you have:
spring.profiles.active=${profiles.active}
${profiles.active} reference an external property. Check the link I provided to see how external config works. By example, if you deploy in AWS, you can set environment variables via the console, if you deploy with Tomcat, you will have an XML configuration file under Tomcat/conf/Catalina/localhost, ...
If the variable is empty, default profile is used and the class tagged with "cron" won't be loaded.
Regarding the different environments
As a rule of thumb, you should always externalize the properties that differs from env to env. In your case it is myservice.lmsurl. This url change for every deployment environment. So it is a good candidate to externalize. In your application.properties you have:
myservice.lmsurl=${myservice.lmsurl}
${myservice.lmsurl} tells Spring that he will have to look for this value somewhere. The order of location is in the link I gave to Spring docs. In each of your environment you have to defined the value the same way as for ${profiles.active}.
Example with Tomcat, in yourApplication.xml:
<?xml version="1.0" encoding="UTF-8"?>
<Context>
<Environment name="profiles.active" value="cron" type="java.lang.String"/>
<Environment name="myservice.lmsurl" value="https://test.com" type="java.lang.String"/>
</Context>
This EXTERNAL file will be different for each environment.
Answered By - Mannekenpix