☕ #cron - Cron Directive (Java)

Java Documentation

#cron - Cron Directive (Java)

The #cron directive provides enterprise-grade scheduled task capabilities for Java applications, enabling automated job execution with Spring Boot integration and comprehensive scheduling features.

Basic Syntax

Basic cron job - every minute

#cron " *" { @cleanup_temp_files() }

Cron with custom schedule

#cron "0 2 *" { @backup_database() }

Cron with conditions

#cron "0 0 *" if: @is_production() { @generate_daily_report() }

Java Implementation

import org.tusklang.java.TuskLang;
import org.tusklang.java.directives.CronDirective;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableScheduling;

@Configuration @EnableScheduling public class SchedulingConfiguration { // Spring Boot scheduling configuration }

@Component public class CronJobs { private final TuskLang tuskLang; private final CronDirective cronDirective; private final CleanupService cleanupService; private final BackupService backupService; private final ReportService reportService; public CronJobs(TuskLang tuskLang, CleanupService cleanupService, BackupService backupService, ReportService reportService) { this.tuskLang = tuskLang; this.cronDirective = new CronDirective(); this.cleanupService = cleanupService; this.backupService = backupService; this.reportService = reportService; } // Basic cron job - every minute @Scheduled(cron = " *") public void cleanupTempFiles() { cleanupService.cleanupTempFiles(); } // Cron with custom schedule - daily at 2 AM @Scheduled(cron = "0 2 *") public void backupDatabase() { backupService.backupDatabase(); } // Cron with conditions - daily at midnight, only in production @Scheduled(cron = "0 0 *") public void generateDailyReport() { if (environmentService.isProduction()) { reportService.generateDailyReport(); } } }

Cron Configuration

Detailed cron configuration

#cron { schedule: "0 0 *" # Cron expression timezone: "UTC" # Timezone enabled: true # Enable/disable job retry: 3 # Retry attempts timeout: 300 # Timeout in seconds } { @complex_scheduled_task() }

Multiple schedules

#cron { schedules: [ "0 0 *", # Daily at midnight "0 6 *", # Daily at 6 AM "0 12 *" # Daily at noon ] } { @multi_schedule_task() }

Conditional scheduling

#cron { schedule: "0 2 *" condition: @is_backup_window() fallback: "0 3 *" } { @conditional_backup() }

Java Cron Configuration

import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;
import org.springframework.scheduling.annotation.Scheduled;
import java.util.List;
import java.util.Map;
import java.util.TimeZone;

@Component @ConfigurationProperties(prefix = "tusk.cron") public class CronConfig { private String defaultTimezone = "UTC"; private boolean defaultEnabled = true; private int defaultRetry = 3; private int defaultTimeout = 300; private Map<String, CronJobDefinition> jobs; private List<String> enabledJobs; private Map<String, String> timezones; // Getters and setters public String getDefaultTimezone() { return defaultTimezone; } public void setDefaultTimezone(String defaultTimezone) { this.defaultTimezone = defaultTimezone; } public boolean isDefaultEnabled() { return defaultEnabled; } public void setDefaultEnabled(boolean defaultEnabled) { this.defaultEnabled = defaultEnabled; } public int getDefaultRetry() { return defaultRetry; } public void setDefaultRetry(int defaultRetry) { this.defaultRetry = defaultRetry; } public int getDefaultTimeout() { return defaultTimeout; } public void setDefaultTimeout(int defaultTimeout) { this.defaultTimeout = defaultTimeout; } public Map<String, CronJobDefinition> getJobs() { return jobs; } public void setJobs(Map<String, CronJobDefinition> jobs) { this.jobs = jobs; } public List<String> getEnabledJobs() { return enabledJobs; } public void setEnabledJobs(List<String> enabledJobs) { this.enabledJobs = enabledJobs; } public Map<String, String> getTimezones() { return timezones; } public void setTimezones(Map<String, String> timezones) { this.timezones = timezones; } public static class CronJobDefinition { private String schedule; private String timezone; private boolean enabled = true; private int retry = 3; private int timeout = 300; private String condition; private String fallback; private List<String> schedules; // Getters and setters public String getSchedule() { return schedule; } public void setSchedule(String schedule) { this.schedule = schedule; } public String getTimezone() { return timezone; } public void setTimezone(String timezone) { this.timezone = timezone; } public boolean isEnabled() { return enabled; } public void setEnabled(boolean enabled) { this.enabled = enabled; } public int getRetry() { return retry; } public void setRetry(int retry) { this.retry = retry; } public int getTimeout() { return timeout; } public void setTimeout(int timeout) { this.timeout = timeout; } public String getCondition() { return condition; } public void setCondition(String condition) { this.condition = condition; } public String getFallback() { return fallback; } public void setFallback(String fallback) { this.fallback = fallback; } public List<String> getSchedules() { return schedules; } public void setSchedules(List<String> schedules) { this.schedules = schedules; } } }

@Service public class CronJobService { private final CronConfig config; private final TaskScheduler taskScheduler; private final Map<String, ScheduledTask> scheduledTasks; public CronJobService(CronConfig config, TaskScheduler taskScheduler) { this.config = config; this.taskScheduler = taskScheduler; this.scheduledTasks = new ConcurrentHashMap<>(); } public void scheduleJob(String jobName, CronConfig.CronJobDefinition definition, Runnable task) { if (!definition.isEnabled()) { return; } CronTrigger trigger = createCronTrigger(definition); ScheduledTask scheduledTask = taskScheduler.schedule(task, trigger); scheduledTasks.put(jobName, scheduledTask); } private CronTrigger createCronTrigger(CronConfig.CronJobDefinition definition) { String schedule = definition.getSchedule(); String timezone = definition.getTimezone() != null ? definition.getTimezone() : config.getDefaultTimezone(); return new CronTrigger(schedule, TimeZone.getTimeZone(timezone)); } public void cancelJob(String jobName) { ScheduledTask task = scheduledTasks.get(jobName); if (task != null) { task.cancel(); scheduledTasks.remove(jobName); } } public boolean isJobScheduled(String jobName) { return scheduledTasks.containsKey(jobName); } }

Database Maintenance Jobs

Database cleanup - daily at 3 AM

#cron "0 3 *" { @cleanup_old_records() @optimize_tables() @update_statistics() }

Database backup - daily at 2 AM

#cron "0 2 *" { @backup_database("main_db") @backup_database("analytics_db") @cleanup_old_backups() }

Database maintenance with conditions

#cron { schedule: "0 4 0" # Weekly on Sunday at 4 AM condition: @is_maintenance_window() } { @full_database_maintenance() }

Java Database Maintenance Jobs

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

@Component public class DatabaseMaintenanceJobs { private final DatabaseService databaseService; private final BackupService backupService; private final MaintenanceService maintenanceService; public DatabaseMaintenanceJobs(DatabaseService databaseService, BackupService backupService, MaintenanceService maintenanceService) { this.databaseService = databaseService; this.backupService = backupService; this.maintenanceService = maintenanceService; } // Database cleanup - daily at 3 AM @Scheduled(cron = "0 3 *") @Transactional public void cleanupDatabase() { try { // Cleanup old records databaseService.cleanupOldRecords(); // Optimize tables databaseService.optimizeTables(); // Update statistics databaseService.updateStatistics(); logger.info("Database cleanup completed successfully"); } catch (Exception e) { logger.error("Database cleanup failed", e); throw e; } } // Database backup - daily at 2 AM @Scheduled(cron = "0 2 *") public void backupDatabases() { try { // Backup main database backupService.backupDatabase("main_db"); // Backup analytics database backupService.backupDatabase("analytics_db"); // Cleanup old backups backupService.cleanupOldBackups(); logger.info("Database backup completed successfully"); } catch (Exception e) { logger.error("Database backup failed", e); throw e; } } // Weekly maintenance - Sunday at 4 AM @Scheduled(cron = "0 4 0") public void weeklyMaintenance() { if (maintenanceService.isMaintenanceWindow()) { try { maintenanceService.performFullMaintenance(); logger.info("Weekly maintenance completed successfully"); } catch (Exception e) { logger.error("Weekly maintenance failed", e); throw e; } } else { logger.info("Skipping weekly maintenance - not in maintenance window"); } } }

@Service public class DatabaseService { private final JdbcTemplate jdbcTemplate; private final DataSource dataSource; public DatabaseService(JdbcTemplate jdbcTemplate, DataSource dataSource) { this.jdbcTemplate = jdbcTemplate; this.dataSource = dataSource; } @Transactional public void cleanupOldRecords() { // Delete old log records (older than 90 days) jdbcTemplate.update("DELETE FROM logs WHERE created_at < DATE_SUB(NOW(), INTERVAL 90 DAY)"); // Delete old session data (older than 30 days) jdbcTemplate.update("DELETE FROM sessions WHERE last_accessed < DATE_SUB(NOW(), INTERVAL 30 DAY)"); // Delete old temporary files jdbcTemplate.update("DELETE FROM temp_files WHERE created_at < DATE_SUB(NOW(), INTERVAL 7 DAY)"); } public void optimizeTables() { // Get all table names List<String> tables = jdbcTemplate.queryForList( "SELECT table_name FROM information_schema.tables WHERE table_schema = DATABASE()", String.class ); for (String table : tables) { try { jdbcTemplate.execute("OPTIMIZE TABLE " + table); logger.debug("Optimized table: {}", table); } catch (Exception e) { logger.warn("Failed to optimize table: {}", table, e); } } } public void updateStatistics() { // Update table statistics jdbcTemplate.execute("ANALYZE TABLE"); // Update index statistics jdbcTemplate.execute("ANALYZE TABLE"); } }

@Service public class BackupService { private final DataSource dataSource; private final FileService fileService; public BackupService(DataSource dataSource, FileService fileService) { this.dataSource = dataSource; this.fileService = fileService; } public void backupDatabase(String databaseName) { String backupPath = "/backups/" + databaseName + "_" + LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")) + ".sql"; try { // Create backup directory if it doesn't exist fileService.createDirectoryIfNotExists("/backups"); // Perform database backup ProcessBuilder pb = new ProcessBuilder( "mysqldump", "--host=" + getDatabaseHost(), "--port=" + getDatabasePort(), "--user=" + getDatabaseUser(), "--password=" + getDatabasePassword(), "--single-transaction", "--routines", "--triggers", databaseName ); Process process = pb.start(); // Write backup to file try (FileOutputStream fos = new FileOutputStream(backupPath)) { byte[] buffer = new byte[1024]; int bytesRead; while ((bytesRead = process.getInputStream().read(buffer)) != -1) { fos.write(buffer, 0, bytesRead); } } int exitCode = process.waitFor(); if (exitCode != 0) { throw new RuntimeException("Database backup failed with exit code: " + exitCode); } logger.info("Database backup completed: {}", backupPath); } catch (Exception e) { logger.error("Database backup failed for: {}", databaseName, e); throw new RuntimeException("Database backup failed", e); } } public void cleanupOldBackups() { try { // Keep backups for 30 days LocalDateTime cutoffDate = LocalDateTime.now().minusDays(30); File backupDir = new File("/backups"); if (backupDir.exists()) { File[] backupFiles = backupDir.listFiles((dir, name) -> name.endsWith(".sql")); if (backupFiles != null) { for (File backupFile : backupFiles) { if (backupFile.lastModified() < cutoffDate.toInstant(ZoneOffset.UTC).toEpochMilli()) { backupFile.delete(); logger.info("Deleted old backup: {}", backupFile.getName()); } } } } } catch (Exception e) { logger.error("Failed to cleanup old backups", e); } } private String getDatabaseHost() { // Extract host from datasource return "localhost"; // Simplified } private String getDatabasePort() { return "3306"; // Simplified } private String getDatabaseUser() { return "root"; // Simplified } private String getDatabasePassword() { return "password"; // Simplified } }

Email and Notification Jobs

Daily digest email - 8 AM daily

#cron "0 8 *" { @send_daily_digest() }

Weekly newsletter - Monday at 9 AM

#cron "0 9 1" { @send_weekly_newsletter() }

Notification cleanup - every 6 hours

#cron "0 /6 " { @cleanup_old_notifications() }

Java Email and Notification Jobs

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.mail.javamail.JavaMailSender;

@Component public class EmailNotificationJobs { private final EmailService emailService; private final NotificationService notificationService; private final DigestService digestService; private final NewsletterService newsletterService; public EmailNotificationJobs(EmailService emailService, NotificationService notificationService, DigestService digestService, NewsletterService newsletterService) { this.emailService = emailService; this.notificationService = notificationService; this.digestService = digestService; this.newsletterService = newsletterService; } // Daily digest email - 8 AM daily @Scheduled(cron = "0 8 *") public void sendDailyDigest() { try { List<User> users = userService.getUsersWithDigestEnabled(); for (User user : users) { DailyDigest digest = digestService.generateDailyDigest(user.getId()); emailService.sendDailyDigest(user.getEmail(), digest); } logger.info("Daily digest sent to {} users", users.size()); } catch (Exception e) { logger.error("Failed to send daily digest", e); throw e; } } // Weekly newsletter - Monday at 9 AM @Scheduled(cron = "0 9 1") public void sendWeeklyNewsletter() { try { List<User> subscribers = userService.getNewsletterSubscribers(); WeeklyNewsletter newsletter = newsletterService.generateWeeklyNewsletter(); for (User user : subscribers) { emailService.sendWeeklyNewsletter(user.getEmail(), newsletter); } logger.info("Weekly newsletter sent to {} subscribers", subscribers.size()); } catch (Exception e) { logger.error("Failed to send weekly newsletter", e); throw e; } } // Notification cleanup - every 6 hours @Scheduled(cron = "0 /6 ") public void cleanupOldNotifications() { try { int deletedCount = notificationService.cleanupOldNotifications(); logger.info("Cleaned up {} old notifications", deletedCount); } catch (Exception e) { logger.error("Failed to cleanup old notifications", e); throw e; } } }

@Service public class EmailService { private final JavaMailSender mailSender; private final TemplateEngine templateEngine; public EmailService(JavaMailSender mailSender, TemplateEngine templateEngine) { this.mailSender = mailSender; this.templateEngine = templateEngine; } public void sendDailyDigest(String email, DailyDigest digest) { try { MimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setTo(email); helper.setSubject("Your Daily Digest"); helper.setFrom("noreply@example.com"); // Generate HTML content Context context = new Context(); context.setVariable("digest", digest); String htmlContent = templateEngine.process("daily-digest", context); helper.setText(htmlContent, true); mailSender.send(message); logger.debug("Daily digest sent to: {}", email); } catch (Exception e) { logger.error("Failed to send daily digest to: {}", email, e); throw new RuntimeException("Failed to send daily digest", e); } } public void sendWeeklyNewsletter(String email, WeeklyNewsletter newsletter) { try { MimeMessage message = mailSender.createMimeMessage(); MimeMessageHelper helper = new MimeMessageHelper(message, true); helper.setTo(email); helper.setSubject("Weekly Newsletter"); helper.setFrom("newsletter@example.com"); // Generate HTML content Context context = new Context(); context.setVariable("newsletter", newsletter); String htmlContent = templateEngine.process("weekly-newsletter", context); helper.setText(htmlContent, true); mailSender.send(message); logger.debug("Weekly newsletter sent to: {}", email); } catch (Exception e) { logger.error("Failed to send weekly newsletter to: {}", email, e); throw new RuntimeException("Failed to send weekly newsletter", e); } } }

@Service public class NotificationService { private final JdbcTemplate jdbcTemplate; public NotificationService(JdbcTemplate jdbcTemplate) { this.jdbcTemplate = jdbcTemplate; } public int cleanupOldNotifications() { // Delete notifications older than 30 days return jdbcTemplate.update( "DELETE FROM notifications WHERE created_at < DATE_SUB(NOW(), INTERVAL 30 DAY)" ); } }

Data Processing Jobs

Data aggregation - hourly

#cron "0 " { @aggregate_hourly_data() }

Report generation - daily at 6 AM

#cron "0 6 *" { @generate_daily_reports() }

Data synchronization - every 15 minutes

#cron "/15 *" { @sync_external_data() }

Java Data Processing Jobs

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters;
import org.springframework.batch.core.JobParametersBuilder;
import org.springframework.batch.core.launch.JobLauncher;

@Component public class DataProcessingJobs { private final JobLauncher jobLauncher; private final Job hourlyAggregationJob; private final Job dailyReportJob; private final DataSyncService dataSyncService; public DataProcessingJobs(JobLauncher jobLauncher, Job hourlyAggregationJob, Job dailyReportJob, DataSyncService dataSyncService) { this.jobLauncher = jobLauncher; this.hourlyAggregationJob = hourlyAggregationJob; this.dailyReportJob = dailyReportJob; this.dataSyncService = dataSyncService; } // Data aggregation - hourly @Scheduled(cron = "0 ") public void aggregateHourlyData() { try { JobParameters jobParameters = new JobParametersBuilder() .addLong("timestamp", System.currentTimeMillis()) .toJobParameters(); jobLauncher.run(hourlyAggregationJob, jobParameters); logger.info("Hourly data aggregation completed"); } catch (Exception e) { logger.error("Hourly data aggregation failed", e); throw e; } } // Report generation - daily at 6 AM @Scheduled(cron = "0 6 *") public void generateDailyReports() { try { JobParameters jobParameters = new JobParametersBuilder() .addLong("timestamp", System.currentTimeMillis()) .toJobParameters(); jobLauncher.run(dailyReportJob, jobParameters); logger.info("Daily report generation completed"); } catch (Exception e) { logger.error("Daily report generation failed", e); throw e; } } // Data synchronization - every 15 minutes @Scheduled(cron = "/15 *") public void syncExternalData() { try { dataSyncService.syncExternalData(); logger.info("External data synchronization completed"); } catch (Exception e) { logger.error("External data synchronization failed", e); throw e; } } }

@Service public class DataSyncService { private final ExternalApiClient externalApiClient; private final DataRepository dataRepository; public DataSyncService(ExternalApiClient externalApiClient, DataRepository dataRepository) { this.externalApiClient = externalApiClient; this.dataRepository = dataRepository; } @Transactional public void syncExternalData() { try { // Fetch data from external API List<ExternalData> externalData = externalApiClient.fetchData(); // Process and save data for (ExternalData data : externalData) { DataEntity entity = convertToEntity(data); dataRepository.save(entity); } logger.debug("Synced {} external data records", externalData.size()); } catch (Exception e) { logger.error("Failed to sync external data", e); throw new RuntimeException("External data sync failed", e); } } private DataEntity convertToEntity(ExternalData externalData) { DataEntity entity = new DataEntity(); entity.setExternalId(externalData.getId()); entity.setName(externalData.getName()); entity.setValue(externalData.getValue()); entity.setLastSynced(LocalDateTime.now()); return entity; } }

System Maintenance Jobs

System health check - every 5 minutes

#cron "/5 *" { @check_system_health() }

Log rotation - daily at 1 AM

#cron "0 1 *" { @rotate_logs() }

Cache cleanup - every 2 hours

#cron "0 /2 " { @cleanup_cache() }

Java System Maintenance Jobs

import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;
import org.springframework.cache.CacheManager;

@Component public class SystemMaintenanceJobs { private final HealthCheckService healthCheckService; private final LogRotationService logRotationService; private final CacheManager cacheManager; public SystemMaintenanceJobs(HealthCheckService healthCheckService, LogRotationService logRotationService, CacheManager cacheManager) { this.healthCheckService = healthCheckService; this.logRotationService = logRotationService; this.cacheManager = cacheManager; } // System health check - every 5 minutes @Scheduled(cron = "/5 *") public void checkSystemHealth() { try { HealthStatus healthStatus = healthCheckService.checkSystemHealth(); if (!healthStatus.isHealthy()) { logger.warn("System health check failed: {}", healthStatus.getIssues()); notificationService.sendHealthAlert(healthStatus); } else { logger.debug("System health check passed"); } } catch (Exception e) { logger.error("System health check failed", e); throw e; } } // Log rotation - daily at 1 AM @Scheduled(cron = "0 1 *") public void rotateLogs() { try { logRotationService.rotateLogs(); logger.info("Log rotation completed"); } catch (Exception e) { logger.error("Log rotation failed", e); throw e; } } // Cache cleanup - every 2 hours @Scheduled(cron = "0 /2 ") public void cleanupCache() { try { cacheManager.getCacheNames().forEach(cacheName -> { Cache cache = cacheManager.getCache(cacheName); if (cache != null) { cache.clear(); logger.debug("Cleared cache: {}", cacheName); } }); logger.info("Cache cleanup completed"); } catch (Exception e) { logger.error("Cache cleanup failed", e); throw e; } } }

@Service public class HealthCheckService { private final DataSource dataSource; private final RedisTemplate<String, String> redisTemplate; public HealthCheckService(DataSource dataSource, RedisTemplate<String, String> redisTemplate) { this.dataSource = dataSource; this.redisTemplate = redisTemplate; } public HealthStatus checkSystemHealth() { HealthStatus status = new HealthStatus(); List<String> issues = new ArrayList<>(); // Check database connectivity try { dataSource.getConnection().close(); } catch (Exception e) { issues.add("Database connectivity issue: " + e.getMessage()); } // Check Redis connectivity try { redisTemplate.opsForValue().get("health_check"); } catch (Exception e) { issues.add("Redis connectivity issue: " + e.getMessage()); } // Check disk space File root = new File("/"); long freeSpace = root.getFreeSpace(); long totalSpace = root.getTotalSpace(); double usagePercent = (double) (totalSpace - freeSpace) / totalSpace * 100; if (usagePercent > 90) { issues.add("Disk space usage high: " + String.format("%.1f%%", usagePercent)); } // Check memory usage Runtime runtime = Runtime.getRuntime(); long maxMemory = runtime.maxMemory(); long usedMemory = runtime.totalMemory() - runtime.freeMemory(); double memoryUsagePercent = (double) usedMemory / maxMemory * 100; if (memoryUsagePercent > 85) { issues.add("Memory usage high: " + String.format("%.1f%%", memoryUsagePercent)); } status.setHealthy(issues.isEmpty()); status.setIssues(issues); return status; } }

@Service public class LogRotationService { private final String logDirectory = "/var/log/application"; public void rotateLogs() { try { File logDir = new File(logDirectory); if (!logDir.exists()) { return; } File[] logFiles = logDir.listFiles((dir, name) -> name.endsWith(".log")); if (logFiles == null) { return; } for (File logFile : logFiles) { rotateLogFile(logFile); } // Cleanup old rotated logs (keep for 30 days) cleanupOldRotatedLogs(); } catch (Exception e) { logger.error("Log rotation failed", e); throw new RuntimeException("Log rotation failed", e); } } private void rotateLogFile(File logFile) throws IOException { String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss")); File rotatedFile = new File(logFile.getParent(), logFile.getName() + "." + timestamp); // Move current log to rotated file Files.move(logFile.toPath(), rotatedFile.toPath()); // Create new empty log file logFile.createNewFile(); // Compress rotated file compressFile(rotatedFile); logger.info("Rotated log file: {} -> {}", logFile.getName(), rotatedFile.getName()); } private void compressFile(File file) throws IOException { try (GZIPOutputStream gzipOut = new GZIPOutputStream( new FileOutputStream(file.getAbsolutePath() + ".gz"))) { Files.copy(file.toPath(), gzipOut); } // Delete original file after compression file.delete(); } private void cleanupOldRotatedLogs() { LocalDateTime cutoffDate = LocalDateTime.now().minusDays(30); File logDir = new File(logDirectory); File[] rotatedFiles = logDir.listFiles((dir, name) -> name.endsWith(".gz")); if (rotatedFiles != null) { for (File rotatedFile : rotatedFiles) { if (rotatedFile.lastModified() < cutoffDate.toInstant(ZoneOffset.UTC).toEpochMilli()) { rotatedFile.delete(); logger.info("Deleted old rotated log: {}", rotatedFile.getName()); } } } } }

Cron Job Testing

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.test.context.TestPropertySource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ActiveProfiles;

@SpringBootTest @TestPropertySource(properties = { "tusk.cron.default-enabled=true", "spring.task.scheduling.pool.size=5" }) @ActiveProfiles("test") public class CronJobTest { @Autowired private CronJobs cronJobs; @MockBean private CleanupService cleanupService; @MockBean private BackupService backupService; @MockBean private ReportService reportService; @Test public void testCleanupTempFiles() { // Test cleanup job cronJobs.cleanupTempFiles(); verify(cleanupService).cleanupTempFiles(); } @Test public void testBackupDatabase() { // Test backup job cronJobs.backupDatabase(); verify(backupService).backupDatabase(); } @Test public void testGenerateDailyReport() { // Test report generation job when(environmentService.isProduction()).thenReturn(true); cronJobs.generateDailyReport(); verify(reportService).generateDailyReport(); } @Test public void testGenerateDailyReportNotProduction() { // Test report generation job when not in production when(environmentService.isProduction()).thenReturn(false); cronJobs.generateDailyReport(); verify(reportService, never()).generateDailyReport(); } }

Configuration Properties

application.yml

tusk: cron: default-timezone: "UTC" default-enabled: true default-retry: 3 default-timeout: 300 jobs: database-cleanup: schedule: "0 3 *" timezone: "UTC" enabled: true retry: 3 timeout: 600 database-backup: schedule: "0 2 *" timezone: "UTC" enabled: true retry: 2 timeout: 1800 daily-digest: schedule: "0 8 *" timezone: "America/New_York" enabled: true retry: 3 timeout: 300 weekly-newsletter: schedule: "0 9 1" timezone: "America/New_York" enabled: true retry: 2 timeout: 600 system-health: schedule: "/5 *" timezone: "UTC" enabled: true retry: 1 timeout: 60 enabled-jobs: - "database-cleanup" - "database-backup" - "daily-digest" - "weekly-newsletter" - "system-health" timezones: UTC: "UTC" EST: "America/New_York" PST: "America/Los_Angeles"

spring: task: scheduling: pool: size: 10 thread-name-prefix: "cron-" mail: host: smtp.gmail.com port: 587 username: ${MAIL_USERNAME} password: ${MAIL_PASSWORD} properties: mail: smtp: auth: true starttls: enable: true

Summary

The #cron directive in TuskLang provides comprehensive scheduled task capabilities for Java applications. With Spring Boot integration, flexible scheduling, and support for various job types, you can implement sophisticated automated processes that enhance your application's functionality.

Key features include: - Multiple job types: Database maintenance, email notifications, data processing, and system maintenance - Spring Boot integration: Seamless integration with Spring Boot scheduling - Flexible configuration: Configurable cron expressions with timezone support - Conditional scheduling: Execute jobs based on conditions - Error handling: Retry mechanisms and timeout configuration - Monitoring: Built-in logging and monitoring capabilities - Testing support: Comprehensive testing utilities

The Java implementation provides enterprise-grade scheduling that integrates seamlessly with Spring Boot applications while maintaining the simplicity and power of TuskLang's declarative syntax.