From 7383662c61da573e3534524cddd678e6fa92ce9e Mon Sep 17 00:00:00 2001 From: aalehin Date: Wed, 1 Feb 2023 19:28:58 +0300 Subject: [PATCH] Scheduling update --- .../scheduler/service/TaskManager.java | 326 ++++++++++++------ .../cud/schedule/PlannerNewRequest.java | 11 + .../cud/schedule/PlannerUpdateRequest.java | 12 + 3 files changed, 242 insertions(+), 107 deletions(-) diff --git a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java index bcc7fbc07..9b332b54e 100644 --- a/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java +++ b/clearing-parent/scheduler-service/src/main/java/ru/spcex/clearing/scheduler/service/TaskManager.java @@ -1,36 +1,43 @@ package ru.spcex.clearing.scheduler.service; -import com.hazelcast.core.EntryEvent; -import com.hazelcast.map.listener.EntryAddedListener; -import com.hazelcast.map.listener.EntryRemovedListener; -import com.hazelcast.map.listener.EntryUpdatedListener; +import org.apache.kafka.clients.consumer.Consumer; +import org.apache.kafka.clients.producer.Producer; +import org.apache.kafka.clients.producer.ProducerRecord; +import org.apache.kafka.clients.producer.RecordMetadata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.context.annotation.Lazy; -import org.springframework.lang.NonNull; import org.springframework.scheduling.TaskScheduler; import org.springframework.stereotype.Service; -import ru.clearing.classes.statics.data.scheduler.Launcher; import ru.clearing.classes.statics.data.scheduler.PlannerAllToday; +import ru.spcex.clearing.imdg.IMDGDistributedNames; +import ru.spcex.clearing.platform.messaging.domain.BaseRequest; +import ru.spcex.clearing.platform.messaging.domain.Consts; +import ru.spcex.clearing.platform.messaging.domain.cud.common.CommonDeleteRequest; +import ru.spcex.clearing.platform.messaging.domain.cud.schedule.*; +import ru.spcex.clearing.platform.messaging.service.QueueConsumer; +import ru.spcex.clearing.platform.messaging.service.RequestInfoUpdate; import ru.spcex.platform.enumeration.Status; import ru.spcex.platform.enumeration.Task; import ru.spcex.platform.imdg.api.Imdg; import ru.spcex.platform.imdg.api.ImdgProvider; -import ru.spcex.platform.imdg.iml.hazelcast.adapter.ImdgHazelcast; -import java.time.*; +import java.time.LocalDate; +import java.time.LocalDateTime; +import java.time.LocalTime; +import java.time.ZoneId; import java.util.ArrayList; import java.util.Collection; -import java.util.Date; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.Future; import java.util.concurrent.ScheduledFuture; import java.util.stream.Collectors; -import static ru.spcex.clearing.imdg.IMDGDistributedNames.Map_Launcher; -import static ru.spcex.clearing.imdg.IMDGDistributedNames.Map_PlannerAllToday; +import static ru.spcex.clearing.platform.messaging.domain.Consts.LAUNCHER_NEW; import static ru.spcex.platform.enumeration.Status.*; import static ru.spcex.platform.utils.enumeration.IEnumKey.getEnumByKey; @@ -38,69 +45,187 @@ import static ru.spcex.platform.utils.enumeration.IEnumKey.getEnumByKey; * Планировщик задач, расписание берёт из Hazelcast map. *

*/ -@Service("userReportTask") -@Lazy -public class TaskManager implements EntryAddedListener, - EntryUpdatedListener, EntryRemovedListener, - InitializingBean { - private static final Logger log = LoggerFactory.getLogger(TaskManager.class); +@Service +public class TaskManager extends QueueConsumer implements InitializingBean { + private final Logger log = LoggerFactory.getLogger(getClass()); + private final TaskScheduler taskScheduler; private final ImdgProvider imdgProvider; - private Imdg launcherMap; private Imdg plannerAllTodayMap; private ConcurrentHashMap scheduledJobs; - private LauncherSender launcherSender; + private Producer kafkaProducer; @Autowired - TaskManager(TaskScheduler taskScheduler, - ImdgProvider imdgProvider, - LauncherSender launcherSender) { - this.taskScheduler = taskScheduler; + public TaskManager(TaskScheduler taskScheduler, + Consumer kafkaQueue, + Producer kafkaProducer, + ImdgProvider imdgProvider) { + super(kafkaQueue, kafkaProducer); this.imdgProvider = imdgProvider; - this.launcherSender = launcherSender; + this.taskScheduler = taskScheduler; + this.kafkaProducer = kafkaProducer; } - private static LocalDateTime dateOldTypeConvert(@NonNull Date oldDate) { - return LocalDateTime.ofInstant(oldDate.toInstant(), ZoneId.systemDefault()); - } - - private static LocalDate dateTypeConvert(@NonNull Date oldDate) { - return dateOldTypeConvert(oldDate).toLocalDate(); - } - - private static LocalTime timeTypeConvert(@NonNull Date oldDate) { - return dateOldTypeConvert(oldDate).toLocalTime(); - } @Override - public void afterPropertiesSet() { - this.launcherMap = imdgProvider.getImdg(Map_Launcher, Launcher.class); - this.plannerAllTodayMap = imdgProvider.getImdg(Map_PlannerAllToday, PlannerAllToday.class); - if (plannerAllTodayMap instanceof ImdgHazelcast plannerAllTodayImdgHazelcast) { - plannerAllTodayImdgHazelcast.getMap().addEntryListener(this, true); - } + public void afterPropertiesSet() throws Exception { + plannerAllTodayMap = imdgProvider.getImdg(IMDGDistributedNames.Map_PlannerAllToday, PlannerAllToday.class); scheduledJobs = new ConcurrentHashMap<>(); updateScheduler(); + callback(PlannerNewRequest.class) + .setFunction(this::newPlanner) + .forDestination(Consts.DESTINATION_PLANNER_NEW, callbacks::put);//fixme + callback(PlannerUpdateRequest.class) + .setFunction(this::updatePlanner) + .forDestination(Consts.DESTINATION_PLANNER_UPDATE, callbacks::put);//fixme + callback(CommonDeleteRequest.class) + .setFunction(this::deletePlanner) + .forDestination(Consts.DESTINATION_PLANNER_DELETE, callbacks::put);//fixme + callback(PlannerTemplateNewRequest.class) + .setFunction(this::newPlannerTemplate) + .forDestination(Consts.DESTINATION_PLANNER_TEMPLATE_NEW, callbacks::put); + callback(PlannerTemplateUpdateRequest.class) + .setFunction(this::updatePlannerTemplate) + .forDestination(Consts.DESTINATION_PLANNER_TEMPLATE_UPDATE, callbacks::put); + callback(CommonDeleteRequest.class) + .setFunction(this::deletePlannerTemplate) + .forDestination(Consts.DESTINATION_PLANNER_TEMPLATE_DELETE, callbacks::put); + callback(ClearingCalendarNewRequest.class) + .setFunction(this::newClearingCalendar) + .forDestination(Consts.DESTINATION_CLEARING_CALENDAR_NEW, callbacks::put); + callback(ClearingCalendarUpdateRequest.class) + .setFunction(this::updateClearingCalendar) + .forDestination(Consts.DESTINATION_CLEARING_CALENDAR_UPDATE, callbacks::put); + callback(CommonDeleteRequest.class) + .setFunction(this::deleteClearingCalendar) + .forDestination(Consts.DESTINATION_CLEARING_CALENDAR_DELETE, callbacks::put); + init(); } - // --- Слушатели Hazelcast Map --- - @Override - public void entryAdded(EntryEvent event) { - PlannerAllToday task = event.getValue(); + // --- Планирование задач --- + protected void updateScheduler() { + Collection schedulerAllTodays = plannerAllTodayMap.getAllValues(); + Collection sortedSchedulers = + schedulerAllTodays.stream().sorted((o1, o2) -> (Active.equalsByKey(o1.getTaskStatus()) && Cancel.equalsByKey(o2.getTaskStatus())) ? -1 : 0) + .collect(Collectors.toCollection(ArrayList::new)); + for (PlannerAllToday schedulerAllToday : sortedSchedulers) { + processTask(schedulerAllToday); + } + } + + public RequestInfoUpdate newPlanner(BaseRequest userRequest) { + RequestInfoUpdate requestInfoUpdate = new RequestInfoUpdate(); + PlannerNewRequest request = userRequest.getRequestPayload(); + PlannerAllToday plannerAllToday = new PlannerAllToday(); + plannerAllToday.setTask(request.getTask()); + plannerAllToday.setTaskTime(request.getTaskTime()); + plannerAllToday.setClearingDate(request.getClearingDate()); + plannerAllToday.setMarket(request.getMarket()); + plannerAllToday.setTaskStatus(request.getTaskStatus()); + plannerAllToday.setCompanyId(request.getCompanyId()); + plannerAllToday.setSecurityId(request.getSecurityId()); + plannerAllToday.setParent("PLNR"); + plannerAllToday.setParentId(request.getParentId()); + + processTask(plannerAllToday); + + return requestInfoUpdate; + } + + protected RequestInfoUpdate updatePlanner(BaseRequest userRequest) { + RequestInfoUpdate requestInfoUpdate = new RequestInfoUpdate(); + PlannerUpdateRequest request = userRequest.getRequestPayload(); + PlannerAllToday plannerAllToday = new PlannerAllToday(); + plannerAllToday.setTask(request.getTask()); + plannerAllToday.setTaskTime(request.getTaskTime()); + plannerAllToday.setClearingDate(request.getClearingDate()); + plannerAllToday.setMarket(request.getMarket()); + plannerAllToday.setTaskStatus(request.getTaskStatus()); + plannerAllToday.setCompanyId(request.getCompanyId()); + plannerAllToday.setSecurityId(request.getSecurityId()); + plannerAllToday.setParent("PLNR"); + plannerAllToday.setParentId(request.getParentId()); + return requestInfoUpdate; + + } + + protected RequestInfoUpdate deletePlanner(BaseRequest userRequest) { + RequestInfoUpdate requestInfoUpdate = new RequestInfoUpdate(); + return requestInfoUpdate; + + } + + protected RequestInfoUpdate newPlannerTemplate(BaseRequest userRequest) { + RequestInfoUpdate requestInfoUpdate = new RequestInfoUpdate(); + return requestInfoUpdate; + + } + + protected RequestInfoUpdate updatePlannerTemplate(BaseRequest userRequest) { + RequestInfoUpdate requestInfoUpdate = new RequestInfoUpdate(); + return requestInfoUpdate; + + } + + protected RequestInfoUpdate deletePlannerTemplate(BaseRequest userRequest) { + RequestInfoUpdate requestInfoUpdate = new RequestInfoUpdate(); + return requestInfoUpdate; + + } + + protected RequestInfoUpdate newClearingCalendar(BaseRequest userRequest) { + RequestInfoUpdate requestInfoUpdate = new RequestInfoUpdate(); + return requestInfoUpdate; + + } + + protected RequestInfoUpdate updateClearingCalendar(BaseRequest userRequest) { + RequestInfoUpdate requestInfoUpdate = new RequestInfoUpdate(); + return requestInfoUpdate; + + } + + protected RequestInfoUpdate deleteClearingCalendar(BaseRequest userRequest) { + RequestInfoUpdate requestInfoUpdate = new RequestInfoUpdate(); + + return requestInfoUpdate; + + } + + private void deleteEntry(PlannerAllToday plannerAllToday) { + removeTask(plannerAllToday.getTask(), plannerAllToday.getTaskTime()); + } + + private void newEntry(PlannerAllToday task) { Task taskType = getEnumByKey(Task.class, task.getTask()); if (taskType == null) { log.warn("Task skipped, {} task type not recognized", task.getTask()); return; } + plannerAllTodayMap.insert(task); processTask(task); } - @Override - public void entryUpdated(EntryEvent event) { - PlannerAllToday task = event.getValue(); - PlannerAllToday oldTask = event.getOldValue(); + private void updateEntry(PlannerAllToday plannerAllToday) { + PlannerAllToday task = plannerAllToday; + PlannerAllToday oldTask; + Optional optionalOldTask = plannerAllTodayMap.getAllValues().stream().filter((x) -> { + if (!x.getTaskTime().equals(task.getTaskTime())) { + return false; + } + if (!x.getTask().equalsIgnoreCase(task.getTask())) { + return false; + } + return true; + }).findFirst(); + + if (!optionalOldTask.isPresent()) { + throw new IllegalStateException("Could not find plannerAllToday"); + } + oldTask = optionalOldTask.get(); + task.setId(oldTask.getId()); LocalTime oldTime = oldTask.getTaskTime(); //если таск относится к другому обработчику, пропускаем @@ -114,32 +239,17 @@ public class TaskManager implements EntryAddedListener, } else { log.debug("task with type {}, time {} execution cancelled, adding altered task...", task.getTask(), oldTime.toString()); } + plannerAllTodayMap.update(task); processTask(task); } else if (Cancel.equalsByKey(oldTask.getTaskStatus())) { //&& TaskStatuses.CANCEL.equalsById(task.getTaskStatusId()) restorePreviouslyRemovedTask(oldTime, oldTask); + plannerAllTodayMap.update(task); processTask(task); } else if (Blocked.equalsByKey(oldTask.getTaskStatus())) { + plannerAllTodayMap.update(task); processTask(task); } - } - @Override - public void entryRemoved(EntryEvent event) { - PlannerAllToday taskToRemove = event.getOldValue(); - if (taskToRemove == null) { - log.debug("no task in removed event"); - return; - } - LocalTime removedTaskTime = taskToRemove.getTaskTime(); - - if (Active.equalsByKey(taskToRemove.getTaskStatus())) { - if (removeTask(taskToRemove.getTask(), removedTaskTime)) - log.debug("task successfully canceled"); - } else if (Cancel.equalsByKey(taskToRemove.getTaskStatus())) { - restorePreviouslyRemovedTask(removedTaskTime, taskToRemove); - } else if (Blocked.equalsByKey(taskToRemove.getTaskStatus())) { - log.debug("BLOCKED task removed; do nothing"); - } } private void restorePreviouslyRemovedTask(LocalTime oldTime, PlannerAllToday oldTask) { @@ -154,23 +264,54 @@ public class TaskManager implements EntryAddedListener, } } - // --- Планирование задач --- - protected void updateScheduler() { - Collection schedulerAllTodays = plannerAllTodayMap.getAllValues(); - Collection sortedSchedulers = - schedulerAllTodays.stream().sorted((o1, o2) -> (Active.equalsByKey(o1.getTaskStatus()) && Cancel.equalsByKey(o2.getTaskStatus())) ? -1 : 0) - .collect(Collectors.toCollection(ArrayList::new)); - for (PlannerAllToday schedulerAllToday : sortedSchedulers) { - processTask(schedulerAllToday); + private void removePlannerAllToday(PlannerAllToday plannerAllToday) { + removePlannerAllToday(plannerAllToday.getTask(), plannerAllToday.getTaskTime()); + } + + private void removePlannerAllToday(String task, LocalTime taskTime) { + for (PlannerAllToday x : plannerAllTodayMap.getAllValues()) { + if (x.getTaskTime().equals(taskTime) && x.getTask().equalsIgnoreCase(task)) { + plannerAllTodayMap.delete(x); + break; + } } } - // --- Работа с задачами --- + private boolean removeTask(String task, LocalTime taskTime) { + removePlannerAllToday(task, taskTime); + ScheduledFuture future = scheduledJobs.remove(taskTime); + if (future == null) { + log.debug("can't cancel task type {}, time {}, not found", task, taskTime); + return false; + } + return future.cancel(false); + } + + protected void doJob(PlannerAllToday task) { + Task taskE = getEnumByKey(Task.class, task.getTask()); + if (taskE != null) { + LauncherCommandRequest request = new LauncherCommandRequest(); + request.setTaskName(taskE.name()); + request.setUserId(task.getId()); + log.debug("Send command {} to {}", request, LAUNCHER_NEW); + Future send = kafkaProducer.send(new ProducerRecord<>(LAUNCHER_NEW, request)); + try { + send.get(); + } catch (InterruptedException e) { + Thread.currentThread().interrupt(); + throw new RuntimeException("Command " + request + " not send", e); + } catch (ExecutionException e) { + throw new RuntimeException("Command " + request + " not send", e); + } + } + } + + // --- Работа с тасками --- private void processTask(PlannerAllToday task) { LocalTime taskTime = task.getTaskTime(); Task taskType = getEnumByKey(Task.class, task.getTask()); Status taskStatus = getEnumByKey(Status.class, task.getTaskStatus()); - if (taskStatus == null) throw new IllegalStateException("task status from core can't be null"); + if (taskStatus == null) throw new IllegalStateException("task status can't be null"); if (taskTime.isBefore(LocalTime.now())) { log.debug("Task skipped - taskTime {} is before now, taskType {} ok", taskTime, task.getTask()); return; @@ -210,33 +351,4 @@ public class TaskManager implements EntryAddedListener, log.warn("cancelling task " + (success ? "success" : "fail")); } } - - private boolean removeTask(String task, LocalTime taskTime) { - ScheduledFuture future = scheduledJobs.remove(taskTime); - if (future == null) { - log.debug("can't cancel task type {}, time {}, not found", task, taskTime); - return false; - } - return future.cancel(false); - } - - // --- Реализация выполнения задач --- - - protected void doJob(PlannerAllToday task) { - Task taskE = getEnumByKey(Task.class, task.getTask()); - if (taskE != null) { - log.debug("LauncherCommandRequest received"); - // 1. cохранить команду - Instant created = Instant.now(); - Launcher launcher = new Launcher(); - launcher.setTask(task.getTask()); - launcher.setSenderId(task.getParentId()); - launcher.setCreated(created); - launcher.setUpdated(created); - launcherMap.insert(launcher); - // 2. отправить сообщение - launcherSender.sendCommandToQueue(taskE, task.getParentId()); - log.debug("successfully processed, new id {}", launcher.getId()); - } - } } diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/schedule/PlannerNewRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/schedule/PlannerNewRequest.java index 104469fbc..15ec7096d 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/schedule/PlannerNewRequest.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/schedule/PlannerNewRequest.java @@ -38,6 +38,17 @@ public class PlannerNewRequest { @JsonProperty public Long securityId; + @JsonProperty(required = false) + public Long parentId; + + public Long getParentId() { + return parentId; + } + + public void setParentId(Long parentId) { + this.parentId = parentId; + } + public String getTask() { return task; } diff --git a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/schedule/PlannerUpdateRequest.java b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/schedule/PlannerUpdateRequest.java index 3c186a7a5..a52365efa 100644 --- a/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/schedule/PlannerUpdateRequest.java +++ b/platform-parent/platform-messaging/src/main/java/ru/spcex/clearing/platform/messaging/domain/cud/schedule/PlannerUpdateRequest.java @@ -34,6 +34,18 @@ public class PlannerUpdateRequest { @JsonProperty public Long securityId; + @JsonProperty(required = false) + public Long parentId; + + public Long getParentId() { + return parentId; + } + + public void setParentId(Long parentId) { + this.parentId = parentId; + } + + public Long getId() { return id; }