Solución:
Este es un tema muy amplio. Y hay muchas opciones para lograrlo.
-
Puede configurar su aplicación para tener múltiples perfiles. Por ejemplo, use otro perfil ‘cron’. E inicie su aplicación en un solo servidor con este perfil. Entonces, por ejemplo, en un entorno de producción tiene tres servidores (S1, S2, S3), luego podría ejecutar en S1 con profile prod y cron (
-Dspring.profiles.active=prod,cron
). Y en S2 y S3 solo use el perfil prod (-Dspring.profiles.active=prod
).Y en código, puedes usar
@Profile("cron")
en clases de planificador. De esta manera se ejecutará solo cuando el perfil cron esté activo -
Utilice un candado distribuido. Si tiene Zookeeper en su entorno, puede usar esto para lograr un sistema de bloqueo distribuido.
-
Puede usar alguna base de datos (mysql) y crear un código de muestra para bloquear una de las tablas y agregar una entrada. Y cualquier instancia que obtenga el bloqueo, hará una entrada en esta base de datos y ejecutará el trabajo cron. Debe poner una marca en su código, si
getLock()
es exitoso solo entonces proceda con la ejecución. Mysql tiene utilidades comoLOCK TABLES
, que podría utilizar para salirse con la suya con lecturas / escrituras simultáneas.
personalmente diría que la opción 2 es la mejor de todas.
los Primavera – ShedLock El proyecto se crea específicamente para lograr esto.
Dependencia –
<groupId>net.javacrumbs.shedlock</groupId>
<artifactId>shedlock-spring</artifactId>
Configuración –
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
Implementación –
@Scheduled(cron = "0 0/15 * * * ?")
@SchedulerLock(name = "AnyUniqueName",
lockAtLeastForString = "PT5M", lockAtMostForString = "PT10M")
public void scheduledTask() {
// ...
}
Esto asegurará que solo una instancia deba ejecutar la tarea programada.
Si solo desea una instancia específica, debe ejecutar la tarea del Programador,
Debe configurar su programador para usar el archivo de propiedades y controlar el interruptor del Programador de esta manera:
@ConditionalOnProperty(
value = "scheduling.enabled", havingValue = "true", matchIfMissing = true
)
@Configuration
@EnableScheduling
@EnableSchedulerLock(defaultLockAtMostFor = "PT30S")
public class SchedulingConfig {
Ahora, solo necesita proporcionar una propiedad scheduling.enabled = true
para la instancia desde la que desea que se ejecute Schedular.
La forma más sencilla de hacerlo con Spring es usar una variable de entorno y una anotación de valor:
1 – Obtenga la variable de entorno con la anotación de valor en su clase:
@Value("${TASK_ENABLED}")
private boolean taskEnabled;
2 – Marque el valor taskEnabled para ejecutar la tarea:
@Scheduled(fixedDelay = 50000)
public void myTask() {
if (this.taskEnabled) {
//do stuff here...
}
}
3 – Establezca la variable de entorno correcta por servidor:
falso:
java -DTASK_ENABLED=0 -jar software.jar
o
cierto:
java -DTASK_ENABLED=1 -jar software.jar
Ejemplo con una clase de configuración global
Para usar una clase de configuración global, debe decir que spring es un componente con un @Component y anotar un método establecido para pasar el valor al campo estático.
1 – Cree la clase de configuración con campos estáticos:
@Component
public class AppConfiguration {
public static boolean taskEnabled;
@Value("${TASK_ENABLED}")
public void setTaskEnabled(boolean taskEnabled) {
this.taskEnabled = taskEnabled;
}
}
2 – Marque el valor taskEnabled para ejecutar la tarea:
@Scheduled(fixedDelay = 50000)
public void myTask() {
if (AppConfiguration.taskEnabled) {
//do stuff here...
}
}
3 – Establezca la variable de entorno correcta por servidor:
falso:
java -DTASK_ENABLED=0 -jar software.jar
o
cierto:
java -DTASK_ENABLED=1 -jar software.jar