CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-springframework-boot--spring-boot-starter-quartz

Starter for using the Quartz scheduler in Spring Boot applications with auto-configuration support

Pending
Overview
Eval results
Files

scheduler-customization.mddocs/

Scheduler Customization

Interfaces and annotations for customizing scheduler behavior, data sources, and transaction managers. Enables fine-grained control over Quartz configuration beyond what's available through standard properties.

Capabilities

SchedulerFactoryBeanCustomizer

Functional interface that allows programmatic customization of the SchedulerFactoryBean before it's fully initialized.

/**
 * Callback interface for customizing SchedulerFactoryBean
 * Implement this interface to apply custom configuration that cannot be achieved through properties
 */
@FunctionalInterface
public interface SchedulerFactoryBeanCustomizer {

    /**
     * Customize the SchedulerFactoryBean before initialization
     * @param schedulerFactoryBean The scheduler factory bean to customize
     */
    void customize(SchedulerFactoryBean schedulerFactoryBean);
}

Usage Examples:

@Configuration
public class QuartzCustomizerConfiguration {
    
    @Bean
    public SchedulerFactoryBeanCustomizer schedulerCustomizer() {
        return schedulerFactoryBean -> {
            // Set custom scheduler context data
            Map<String, Object> schedulerContextMap = new HashMap<>();
            schedulerContextMap.put("applicationName", "MyApplication");
            schedulerContextMap.put("environment", "production");
            schedulerFactoryBean.setSchedulerContextAsMap(schedulerContextMap);
            
            // Set custom configuration location
            schedulerFactoryBean.setConfigLocation(new ClassPathResource("quartz-custom.properties"));
            
            // Configure application context integration
            schedulerFactoryBean.setApplicationContextSchedulerContextKey("applicationContext");
            
            // Set custom scheduler listeners
            schedulerFactoryBean.setGlobalJobListeners(new CustomJobListener());
            schedulerFactoryBean.setGlobalTriggerListeners(new CustomTriggerListener());
        };
    }
    
    @Bean
    public SchedulerFactoryBeanCustomizer dataSourceCustomizer(
            @Qualifier("quartzDataSource") DataSource quartzDataSource) {
        return schedulerFactoryBean -> {
            schedulerFactoryBean.setDataSource(quartzDataSource);
            schedulerFactoryBean.setNonTransactionalDataSource(quartzDataSource);
        };
    }
    
    @Bean
    public SchedulerFactoryBeanCustomizer threadPoolCustomizer() {
        return schedulerFactoryBean -> {
            Properties quartzProperties = new Properties();
            quartzProperties.setProperty("org.quartz.threadPool.threadCount", "20");
            quartzProperties.setProperty("org.quartz.threadPool.threadPriority", "5");
            quartzProperties.setProperty("org.quartz.threadPool.class", 
                "org.quartz.simpl.SimpleThreadPool");
            
            schedulerFactoryBean.setQuartzProperties(quartzProperties);
        };
    }
}

QuartzDataSource Annotation

Qualifier annotation for specifying a dedicated DataSource for Quartz operations, separate from the application's primary DataSource.

/**
 * Qualifier annotation for DataSource to be injected into Quartz auto-configuration
 * Used when you want to use a separate database for Quartz job storage
 * Can be applied to secondary DataSource when another is marked as @Primary
 */
@Target({ 
    ElementType.FIELD, 
    ElementType.METHOD, 
    ElementType.PARAMETER, 
    ElementType.TYPE, 
    ElementType.ANNOTATION_TYPE 
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier
public @interface QuartzDataSource {
}

Usage Examples:

@Configuration
public class DataSourceConfiguration {
    
    // Primary DataSource for application data
    @Bean
    @Primary
    @ConfigurationProperties("spring.datasource")
    public DataSource primaryDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    // Dedicated DataSource for Quartz
    @Bean
    @QuartzDataSource
    @ConfigurationProperties("spring.datasource.quartz")
    public DataSource quartzDataSource() {
        return DataSourceBuilder.create().build();
    }
    
    // Using QuartzDataSource in custom components
    @Service
    public class QuartzManagementService {
        
        private final JdbcTemplate quartzJdbcTemplate;
        
        public QuartzManagementService(@QuartzDataSource DataSource quartzDataSource) {
            this.quartzJdbcTemplate = new JdbcTemplate(quartzDataSource);
        }
        
        public List<String> getJobNames() {
            return quartzJdbcTemplate.queryForList(
                "SELECT JOB_NAME FROM QRTZ_JOB_DETAILS", String.class);
        }
    }
}
# Primary database configuration
spring.datasource.url=jdbc:postgresql://localhost:5432/myapp
spring.datasource.username=app_user
spring.datasource.password=app_password

# Quartz database configuration
spring.datasource.quartz.url=jdbc:postgresql://localhost:5432/quartz
spring.datasource.quartz.username=quartz_user
spring.datasource.quartz.password=quartz_password

QuartzTransactionManager Annotation

Qualifier annotation for specifying a dedicated PlatformTransactionManager for Quartz operations.

/**
 * Qualifier annotation for TransactionManager to be injected into Quartz auto-configuration
 * Used when you want to use a separate transaction manager for Quartz operations
 * Can be applied to secondary transaction manager when another is marked as @Primary
 */
@Target({ 
    ElementType.FIELD, 
    ElementType.METHOD, 
    ElementType.PARAMETER, 
    ElementType.TYPE, 
    ElementType.ANNOTATION_TYPE 
})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Qualifier
public @interface QuartzTransactionManager {
}

Usage Examples:

@Configuration
@EnableTransactionManagement
public class TransactionManagerConfiguration {
    
    // Primary transaction manager for application
    @Bean
    @Primary
    public PlatformTransactionManager primaryTransactionManager(
            @Primary DataSource primaryDataSource) {
        return new DataSourceTransactionManager(primaryDataSource);
    }
    
    // Dedicated transaction manager for Quartz
    @Bean
    @QuartzTransactionManager
    public PlatformTransactionManager quartzTransactionManager(
            @QuartzDataSource DataSource quartzDataSource) {
        DataSourceTransactionManager txManager = new DataSourceTransactionManager(quartzDataSource);
        txManager.setNestedTransactionAllowed(true);
        return txManager;
    }
    
    // JTA transaction manager for distributed transactions
    @Bean
    @QuartzTransactionManager
    public JtaTransactionManager quartzJtaTransactionManager() {
        JtaTransactionManager jtaTxManager = new JtaTransactionManager();
        jtaTxManager.setAllowCustomIsolationLevels(true);
        return jtaTxManager;
    }
}

// Using in a custom job with transaction support
@Component
public class TransactionalJob implements Job {
    
    @Autowired
    @QuartzTransactionManager
    private PlatformTransactionManager quartzTransactionManager;
    
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
        TransactionTemplate transactionTemplate = 
            new TransactionTemplate(quartzTransactionManager);
        
        transactionTemplate.execute(status -> {
            // Perform transactional operations
            processData();
            updateJobStatus();
            return null;
        });
    }
}

Advanced Customization Patterns

Custom Job Factory

@Configuration
public class CustomJobFactoryConfiguration {
    
    @Bean
    public SchedulerFactoryBeanCustomizer jobFactoryCustomizer(
            ApplicationContext applicationContext) {
        return schedulerFactoryBean -> {
            CustomSpringBeanJobFactory jobFactory = new CustomSpringBeanJobFactory();
            jobFactory.setApplicationContext(applicationContext);
            schedulerFactoryBean.setJobFactory(jobFactory);
        };
    }
}

public class CustomSpringBeanJobFactory extends SpringBeanJobFactory {
    
    @Override
    protected Object createJobInstance(TriggerFiredBundle bundle) throws Exception {
        Object jobInstance = super.createJobInstance(bundle);
        
        // Apply custom initialization logic
        if (jobInstance instanceof CustomInitializable) {
            ((CustomInitializable) jobInstance).initialize();
        }
        
        return jobInstance;
    }
}

Scheduler Listeners

@Configuration
public class SchedulerListenerConfiguration {
    
    @Bean
    public SchedulerFactoryBeanCustomizer listenerCustomizer() {
        return schedulerFactoryBean -> {
            schedulerFactoryBean.setSchedulerListeners(
                new CustomSchedulerListener()
            );
            
            schedulerFactoryBean.setGlobalJobListeners(
                new CustomJobListener(),
                new AuditJobListener()
            );
            
            schedulerFactoryBean.setGlobalTriggerListeners(
                new CustomTriggerListener()
            );
        };
    }
}

public class CustomSchedulerListener implements SchedulerListener {
    private static final Logger logger = LoggerFactory.getLogger(CustomSchedulerListener.class);
    
    @Override
    public void schedulerStarted() {
        logger.info("Scheduler started successfully");
        // Perform startup tasks
    }
    
    @Override
    public void schedulerShutdown() {
        logger.info("Scheduler shutting down");
        // Perform cleanup tasks
    }
    
    // Other methods...
}

Plugin Configuration

@Configuration
public class QuartzPluginConfiguration {
    
    @Bean
    public SchedulerFactoryBeanCustomizer pluginCustomizer() {
        return schedulerFactoryBean -> {
            Properties properties = new Properties();
            
            // Job initialization plugin
            properties.setProperty("org.quartz.plugin.jobInitializer.class",
                "org.quartz.plugins.xml.XMLSchedulingDataProcessorPlugin");
            properties.setProperty("org.quartz.plugin.jobInitializer.fileNames",
                "jobs.xml");
            properties.setProperty("org.quartz.plugin.jobInitializer.failOnFileNotFound",
                "true");
            
            // Logging plugin
            properties.setProperty("org.quartz.plugin.triggHistory.class",
                "org.quartz.plugins.history.LoggingTriggerHistoryPlugin");
            properties.setProperty("org.quartz.plugin.triggHistory.triggerFiredMessage",
                "Trigger {1}.{0} fired job {6}.{5} at: {4, date, HH:mm:ss MM/dd/yyyy}");
            
            schedulerFactoryBean.setQuartzProperties(properties);
        };
    }
}

Conditional Customization

@Configuration
public class ConditionalQuartzConfiguration {
    
    @Bean
    @ConditionalOnProperty(name = "app.quartz.clustering.enabled", havingValue = "true")
    public SchedulerFactoryBeanCustomizer clusteringCustomizer() {
        return schedulerFactoryBean -> {
            Properties clusterProps = new Properties();
            clusterProps.setProperty("org.quartz.jobStore.isClustered", "true");
            clusterProps.setProperty("org.quartz.jobStore.clusterCheckinInterval", "20000");
            clusterProps.setProperty("org.quartz.scheduler.instanceId", "AUTO");
            
            schedulerFactoryBean.setQuartzProperties(clusterProps);
        };
    }
    
    @Bean
    @ConditionalOnMissingBean(name = "quartzDataSource")
    public SchedulerFactoryBeanCustomizer memoryJobStoreCustomizer() {
        return schedulerFactoryBean -> {
            Properties memoryProps = new Properties();
            memoryProps.setProperty("org.quartz.jobStore.class", 
                "org.quartz.simpl.RAMJobStore");
            
            schedulerFactoryBean.setQuartzProperties(memoryProps);
        };
    }
}

Error Handling and Best Practices

Customizer Ordering

@Configuration
public class OrderedCustomizerConfiguration {
    
    @Bean
    @Order(1)
    public SchedulerFactoryBeanCustomizer dataSourceCustomizer() {
        return schedulerFactoryBean -> {
            // Configure DataSource first
        };
    }
    
    @Bean
    @Order(2)  
    public SchedulerFactoryBeanCustomizer propertiesCustomizer() {
        return schedulerFactoryBean -> {
            // Configure properties after DataSource
        };
    }
    
    @Bean
    @Order(3)
    public SchedulerFactoryBeanCustomizer listenersCustomizer() {
        return schedulerFactoryBean -> {
            // Configure listeners last
        };
    }
}

Error Handling

@Bean
public SchedulerFactoryBeanCustomizer safeCustomizer() {
    return schedulerFactoryBean -> {
        try {
            // Apply customizations
            schedulerFactoryBean.setSchedulerName("CustomScheduler");
        } catch (Exception e) {
            logger.error("Failed to customize scheduler", e);
            // Fallback to default configuration
        }
    };
}

Install with Tessl CLI

npx tessl i tessl/maven-org-springframework-boot--spring-boot-starter-quartz

docs

actuator-integration.md

auto-configuration.md

configuration-properties.md

index.md

scheduler-customization.md

tile.json