package com.sungardas.enhancedsnapshots.service.impl; import com.amazonaws.AmazonClientException; import com.sungardas.enhancedsnapshots.aws.dynamodb.model.TaskEntry; import com.sungardas.enhancedsnapshots.aws.dynamodb.repository.TaskRepository; import com.sungardas.enhancedsnapshots.dto.ExceptionDto; import com.sungardas.enhancedsnapshots.exception.EnhancedSnapshotsException; import com.sungardas.enhancedsnapshots.service.*; import com.sungardas.enhancedsnapshots.util.SystemUtils; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.joda.time.DateTime; import org.springframework.beans.BeanUtils; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.context.annotation.DependsOn; import org.springframework.scheduling.TaskScheduler; import org.springframework.scheduling.support.CronTrigger; import org.springframework.stereotype.Service; import java.util.*; import java.util.concurrent.ScheduledFuture; import java.util.stream.Collectors; @Service @DependsOn("ConfigurationMediator") public class SpringSchedulerService implements SchedulerService, MasterInitialization { private static final Logger LOG = LogManager.getLogger(SpringSchedulerService.class); @Qualifier("taskScheduler") @Autowired private TaskScheduler scheduler; @Autowired private TaskRepository taskRepository; private Map<String, ScheduledFuture> jobs = new HashMap<>(); @Autowired private VolumeService volumeService; @Autowired private NotificationService notificationService; @Autowired private TaskService taskService; @Override public void init() { if (!SystemUtils.clusterMode()) { try { List<TaskEntry> tasks = taskRepository.findByRegular(Boolean.TRUE.toString()); for (TaskEntry taskEntry : tasks) { try { addTask(taskEntry); } catch (EnhancedSnapshotsException e) { LOG.error(e); } } } catch (AmazonClientException e) { LOG.error(e); } } } @Override public void addTask(TaskEntry taskEntry) { if (TaskEntry.TaskEntryType.BACKUP.getType().equals(taskEntry.getType()) && taskEntry.getCron() != null && !taskEntry.getCron().isEmpty()) { if (Boolean.valueOf(taskEntry.getEnabled())) { addTask(new TaskImpl(taskEntry), taskEntry.getCron()); } volumeService.expireCache(); } else { throw new EnhancedSnapshotsException("Invalid task: " + taskEntry); } } @Override public void addTask(Task task, String cronExpression) { addTask(task, new CronTrigger("0 " + cronExpression)); } @Override public void addTask(Task task, CronTrigger cron) { ScheduledFuture<?> future = scheduler.schedule(task, cron); jobs.put(task.getId(), future); } @Override public void removeTask(String id) { ScheduledFuture future = jobs.remove(id); if (future != null) { future.cancel(false); volumeService.expireCache(); } else { LOG.debug("Task with id: {} not found", id); } } @Override public Set<String> getVolumeIdsWithSchedule() { Set<String> result = taskRepository.findByRegularAndEnabled(Boolean.TRUE.toString(), Boolean.TRUE.toString()).stream().map(TaskEntry::getVolume).collect(Collectors.toSet()); return result; } @Override public boolean exists(String taskId) { return jobs.containsKey(taskId); } private class TaskImpl implements Task { private TaskEntry taskEntry; public TaskImpl(TaskEntry taskEntry) { this.taskEntry = taskEntry; } @Override public void run() { if (!volumeService.volumeExists(taskEntry.getVolume())) { LOG.info("Volume {} does not exist any more. Removing scheduler [{}] [] for backups.", taskEntry.getVolume(), taskEntry.getSchedulerName(), taskEntry.getCron()); taskRepository.delete(taskEntry.getId()); removeTask(taskEntry.getId()); return; } if (taskService.isQueueFull()) { notificationService.notifyAboutError(new ExceptionDto("Task creation error", "Task queue is full")); } else { TaskEntry newTask = new TaskEntry(); BeanUtils.copyProperties(taskEntry, newTask); newTask.setId(UUID.randomUUID().toString()); newTask.setSchedulerManual(false); newTask.setRegular(false); newTask.setSchedulerTime(String.valueOf(DateTime.now().getMillis())); taskRepository.save(newTask); } } @Override public String getId() { return taskEntry.getId(); } } }