es.davy.ai

Preguntas y respuestas de programación confiables

¿Tienes una pregunta?

Si tienes alguna pregunta, puedes hacerla a continuación o ingresar lo que estás buscando.

¿Cómo programar los trabajos de cron de Quartz al inicio de una aplicación Spring Boot?

Estoy integrando Quartz con Spring Boot y Postgres. He creado todas las tablas necesarias para el Quartz.

Problema: La aplicación se inicia pero el trabajo no se ejecuta según el cron.

Quiero que los trabajos se programen automáticamente al inicio y se ejecuten según la expresión del cron. Pero por ahora, la aplicación se inicia y no se dispara ninguna orden.

La clase QuartzJobFactory:

public class QuartzJobFactory extends SpringBeanJobFactory implements ApplicationContextAware {
private transient AutowireCapableBeanFactory beanFactory;

@Override
public void setApplicationContext (ApplicationContext applicationContext) throws BeansException {

    beanFactory = applicationContext.getAutowireCapableBeanFactory();
}

@Override
protected Object createJobInstance (TriggerFiredBundle bundle) throws Exception {

    final Object job = super.createJobInstance(bundle);
    beanFactory.autowireBean(job);
    return job;
}
}

La clase ConfigQuartz:

@Configuration
public class ConfigQuartz {

@Value("${quartz.dataSource.myDS.URL}")
String orgQuartzDatasourceMydsUrl;

@Value("${spring.datasource.username}")
String orgQuartzDatasourceMydsUser;

@Value("${spring.datasource.password}")
String orgQuartzDatasourceMydsPassword;

@Value("${quartz.enabled}")
Boolean isQuartzEnabled;

private static List<trigger> triggers = new ArrayList<>();

@Bean
public JobFactory jobFactory (ApplicationContext applicationContext) {
    QuartzJobFactory sampleJobFactory = new QuartzJobFactory();
    sampleJobFactory.setApplicationContext(applicationContext);
    return sampleJobFactory;
}

@Bean
public SchedulerFactoryBean schedulerFactoryBean(DataSource dataSource, JobFactory jobFactory)
        throws IOException {
    SchedulerFactoryBean factory = new SchedulerFactoryBean();
    factory.setOverwriteExistingJobs(true);
    factory.setAutoStartup(isQuartzEnabled);

        factory.setJobFactory(jobFactory);
        factory.setQuartzProperties(quartzProperties());
        factory.setTriggers(triggers.toArray(new Trigger[triggers.size()]));

    return factory;
}

public Properties setQuartzProperties () {
    Properties properties = new Properties();
    properties.setProperty("org.quartz.dataSource.myDS.URL", orgQuartzDatasourceMydsUrl);
    properties.setProperty("org.quartz.dataSource.myDS.user", orgQuartzDatasourceMydsUser);
    properties.setProperty("org.quartz.dataSource.myDS.password", orgQuartzDatasourceMydsPassword);
    return properties;
}

@Bean
public Properties quartzProperties() throws IOException {
    PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
    propertiesFactoryBean.setLocation(new ClassPathResource("quartz.properties"));
    propertiesFactoryBean.setProperties(setQuartzProperties());
    propertiesFactoryBean.afterPropertiesSet();
    return propertiesFactoryBean.getObject();
}

public static SimpleTriggerFactoryBean createTrigger (JobDetail jobDetail, long pollFrequencyMs, String triggerName) {
    SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
    factoryBean.setJobDetail(jobDetail);
    factoryBean.setStartDelay(0L);
    factoryBean.setRepeatInterval(pollFrequencyMs);
    factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
    factoryBean.setName(triggerName);
    factoryBean.setMisfireInstruction(
            SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);
    return factoryBean;
}

public static CronTriggerFactoryBean createCronTrigger (JobDetail jobDetail, String cronExpression, String triggerName) throws Exception {
    CronTriggerFactoryBean factoryBean = new CronTriggerFactoryBean();
    factoryBean.setJobDetail(jobDetail);
    factoryBean.setCronExpression(cronExpression);
    factoryBean.setMisfireInstruction(SimpleTrigger.MISFIRE_INSTRUCTION_FIRE_NOW);
    factoryBean.setName(triggerName);
    try {
        factoryBean.afterPropertiesSet();
    } catch (ParseException e) {
        throw new Exception(e.getMessage());
    }
    triggers.add(factoryBean.getObject());
    return factoryBean;
}

public static JobDetailFactoryBean createJobDetail (Class jobClass) {
    JobDetailFactoryBean factoryBean = new JobDetailFactoryBean();
    factoryBean.setJobClass(jobClass);
    factoryBean.setDurability(true);
    return factoryBean;
}
}

La clase CronExpression:

public class CronExpression {
    private static final Map<string, string=""> cronExpressionMap = ImmutableMap
            .<string, string="">builder()
            .put(TestJob.CLASS_NAME, "* 0 0 ? * * *")
            .build();

public static String get (String key) {
    return cronExpressionMap.get(key);
}
}

La clase TestJob:

@Component
@DisallowConcurrentExecution
public class TestJob implements Job {
public static final String CLASS_NAME = "TestJob";
private final String JOB_BEAN_NAME = CLASS_NAME + AppConstants.QUARTZ_JOB_SUFFIX;
private final String TRIGGER_BEAN_NAME = CLASS_NAME + AppConstants.QUARTZ_TRIGGER_SUFFIX;

@Override
public void execute (JobExecutionContext jobExecutionContext) throws JobExecutionException {
    LocalDateTime start = LocalDateTime.now();
    System.out.println("*************** execute method is running *******");
}

@Bean(name = JOB_BEAN_NAME)
public JobDetailFactoryBean sampleJob () {
    return ConfigQuartz.createJobDetail(this.getClass());
}

@Bean(name = TRIGGER_BEAN_NAME)
public CronTriggerFactoryBean sampleJobTrigger (
        @Qualifier(JOB_BEAN_NAME) JobDetailFactoryBean jobDetail) throws Exception {
    return ConfigQuartz.createCronTrigger(jobDetail.getObject(), CronExpression.get(CLASS_NAME),
            CLASS_NAME);
}
}

La clase principal:
“`
@EnableConfigurationProperties
@EntityScan(basePackages = {“com.example”})
@ComponentScan({“com.example”})
@SpringBootApplication
@EnableScheduling
public class QuartzSchedulerApplication {

public static void main (String[] args) {
SpringApplication</string,></string,>

Tags:  , , , ,

Answer

  1. Avatar for davy.ai

    El problema con el código dado es que aunque se han creado todas las tablas necesarias para Quartz, los trabajos no se están programando automáticamente al iniciar y no se están ejecutando según la expresión cron dada.

    Para programar automáticamente trabajos al inicio y ejecutarlos según la expresión cron, podemos hacer los siguientes cambios en el código existente:

    1. Añadir la anotación @Scheduled a la clase TestJob y proporcionar la expresión cron como parámetro a la anotación.
    @Component
    @DisallowConcurrentExecution
    public class TestJob implements Job {
    
        public static final String CLASS_NAME = "TestJob";
    
        // Añadir esta anotación
        @Scheduled(cron = "0/10 * * * * ?")
        @Override
        public void execute(JobExecutionContext jobExecutionContext) throws JobExecutionException {
            LocalDateTime start = LocalDateTime.now();
            System.out.println("*************** execute method is running *******");
        }
    }
    
    1. Eliminar el método createCronTrigger() de la clase ConfigQuartz y reemplazarlo con un método @Bean para cada trabajo. Añadir la anotación @Scheduled a este método y proporcionar la expresión cron como parámetro a la anotación.
    @Configuration
    public class ConfigQuartz {
    
        // ...
    
        // Eliminar este método
        @Bean(name = TRIGGER_BEAN_NAME)
        public CronTriggerFactoryBean sampleJobTrigger(
                @Qualifier(JOB_BEAN_NAME) JobDetailFactoryBean jobDetail) throws Exception {
            return ConfigQuartz.createCronTrigger(jobDetail.getObject(), CronExpression.get(CLASS_NAME),
                    CLASS_NAME);
        }
    
        // Añadir este método para la clase TestJob
        @Bean
        @SuppressWarnings("SpringFacetCodeInspection")
        public JobDetailFactoryBean testJobDetail() {
            return ConfigQuartz.createJobDetail(TestJob.class);
        }
    
        // Añadir este método para la clase TestJob
        @Bean
        public SimpleTriggerFactoryBean testJobTrigger(@Qualifier("testJobDetail") JobDetail jobDetail) {
            SimpleTriggerFactoryBean factoryBean = new SimpleTriggerFactoryBean();
            factoryBean.setJobDetail(jobDetail);
            factoryBean.setStartDelay(0L);
            factoryBean.setRepeatInterval(10000L);
            factoryBean.setRepeatCount(SimpleTrigger.REPEAT_INDEFINITELY);
            factoryBean.setName("testJobTrigger");
            // En caso de error, ignorar todos los disparadores perdidos y continuar
            factoryBean.setMisfireInstruction(
                    SimpleTrigger.MISFIRE_INSTRUCTION_RESCHEDULE_NEXT_WITH_REMAINING_COUNT);
            return factoryBean;
        }
    }
    
    1. Establecer la propiedad org.quartz.jobStore.isClustered en false en el archivo quartz.properties.
    quartz.jobStore.isClustered = false
    

    Con estos cambios, los trabajos se programarán automáticamente al inicio y se ejecutarán según las expresiones cron dadas. Las anotaciones @Scheduled proporcionan una forma sencilla de especificar el momento de la ejecución de tareas en una aplicación Spring boot.

Comments are closed.