refactor(task): 重构任务监控界面和任务调度逻辑

- 将任务监控界面改为TabPane布局,优化UI结构
- 重构任务调度逻辑,使用统一的ExecutorService
- 修改TaskStatus枚举,将UN_SCHEDULED改为DELAYED
- 优化MonitoredTask实现,改进任务状态管理
- 移除冗余代码,清理无用导入
- 添加调试日志配置
This commit is contained in:
2025-08-22 22:00:03 +08:00
parent 5bed391e64
commit d736f2d3e1
13 changed files with 225 additions and 223 deletions

1
null Normal file
View File

@@ -0,0 +1 @@
Active code page: 65001

View File

@@ -1,18 +1,16 @@
package com.ecep.contract.manager; package com.ecep.contract.manager;
import com.ecep.contract.manager.cloud.CloudRepositoriesConfig; import java.time.Duration;
import com.ecep.contract.manager.ds.DsRepositoriesConfig; import java.time.Instant;
import com.ecep.contract.manager.ui.MessageHolder; import java.time.LocalDate;
import com.ecep.contract.manager.util.MyDateTimeUtils; import java.time.LocalDateTime;
import com.ecep.contract.manager.util.UITools; import java.time.LocalTime;
import com.fasterxml.jackson.databind.ObjectMapper; import java.time.format.DateTimeFormatter;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import java.util.Locale;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer; import java.util.Properties;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer; import java.util.concurrent.CompletableFuture;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer; import java.util.concurrent.ScheduledExecutorService;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
import org.slf4j.Logger; import org.slf4j.Logger;
import org.slf4j.LoggerFactory; import org.slf4j.LoggerFactory;
import org.springframework.beans.BeansException; import org.springframework.beans.BeansException;
@@ -38,17 +36,21 @@ import org.springframework.core.metrics.StartupStep;
import org.springframework.scheduling.annotation.EnableAsync; import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.annotation.EnableScheduling; import org.springframework.scheduling.annotation.EnableScheduling;
import java.time.*; import com.ecep.contract.manager.cloud.CloudRepositoriesConfig;
import java.time.format.DateTimeFormatter; import com.ecep.contract.manager.ds.DsRepositoriesConfig;
import java.util.List; import com.ecep.contract.manager.ui.MessageHolder;
import java.util.Locale; import com.ecep.contract.manager.util.MyDateTimeUtils;
import java.util.Properties; import com.ecep.contract.manager.util.UITools;
import java.util.concurrent.CompletableFuture; import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.concurrent.Executors; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import java.util.concurrent.FutureTask; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
import java.util.concurrent.ScheduledExecutorService; import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalTimeDeserializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalDateTimeSerializer;
import com.fasterxml.jackson.datatype.jsr310.ser.LocalTimeSerializer;
@SpringBootApplication @SpringBootApplication(exclude = { org.springframework.boot.autoconfigure.mail.MailSenderAutoConfiguration.class })
@EnableScheduling @EnableScheduling
@EnableAsync @EnableAsync
@EnableCaching @EnableCaching
@@ -97,7 +99,6 @@ public class SpringApp {
} }
}); });
startup.start(""); startup.start("");
context = application.run(); context = application.run();
logger.debug("SpringApp.launch application.run()."); logger.debug("SpringApp.launch application.run().");
@@ -178,7 +179,8 @@ public class SpringApp {
} }
@Override @Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) { public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {
logger.debug("Desktop.environmentPrepared"); logger.debug("Desktop.environmentPrepared");
debug("初始化 Environment 中,请稍后..."); debug("初始化 Environment 中,请稍后...");
} }
@@ -195,7 +197,6 @@ public class SpringApp {
debug("Spring Application Context 初始化完毕,请稍后..."); debug("Spring Application Context 初始化完毕,请稍后...");
} }
@Override @Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) { public void started(ConfigurableApplicationContext context, Duration timeTaken) {
logger.debug("Desktop.started"); logger.debug("Desktop.started");
@@ -231,7 +232,7 @@ public class SpringApp {
@Bean @Bean
public CacheManager cacheManager() { public CacheManager cacheManager() {
// return new ConcurrentMapCacheManager("myCache"); // return new ConcurrentMapCacheManager("myCache");
CaffeineCacheManager cacheManager = new CaffeineCacheManager(); CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setAsyncCacheMode(true); cacheManager.setAsyncCacheMode(true);
return cacheManager; return cacheManager;
@@ -242,10 +243,12 @@ public class SpringApp {
ObjectMapper objectMapper = new ObjectMapper(); ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule javaTimeModule = new JavaTimeModule(); JavaTimeModule javaTimeModule = new JavaTimeModule();
javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE)); javaTimeModule.addSerializer(LocalDate.class, new LocalDateSerializer(DateTimeFormatter.ISO_LOCAL_DATE));
javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN))); javaTimeModule.addSerializer(LocalDateTime.class, new LocalDateTimeSerializer(
DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN)));
javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss"))); javaTimeModule.addSerializer(LocalTime.class, new LocalTimeSerializer(DateTimeFormatter.ofPattern("HH:mm:ss")));
javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE)); javaTimeModule.addDeserializer(LocalDate.class, new LocalDateDeserializer(DateTimeFormatter.ISO_LOCAL_DATE));
javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN))); javaTimeModule.addDeserializer(LocalDateTime.class, new LocalDateTimeDeserializer(
DateTimeFormatter.ofPattern(MyDateTimeUtils.DEFAULT_DATETIME_FORMAT_PATTERN)));
javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME)); javaTimeModule.addDeserializer(LocalTime.class, new LocalTimeDeserializer(DateTimeFormatter.ISO_LOCAL_TIME));
objectMapper.registerModule(javaTimeModule); objectMapper.registerModule(javaTimeModule);
return objectMapper; return objectMapper;
@@ -253,7 +256,7 @@ public class SpringApp {
@Bean @Bean
public ScheduledExecutorService scheduledExecutorService() { public ScheduledExecutorService scheduledExecutorService() {
return Executors.newScheduledThreadPool(3); return Desktop.instance.getExecutorService();
} }
} }

View File

@@ -1,5 +1,6 @@
package com.ecep.contract.manager.cloud.old; package com.ecep.contract.manager.cloud.old;
import com.ecep.contract.manager.Desktop;
import com.ecep.contract.manager.SpringApp; import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.cloud.rk.CloudRk; import com.ecep.contract.manager.cloud.rk.CloudRk;
import com.ecep.contract.manager.cloud.rk.CloudRkService; import com.ecep.contract.manager.cloud.rk.CloudRkService;
@@ -81,8 +82,6 @@ public class OldVersionService {
@Autowired @Autowired
private CloudTycService cloudTycService; private CloudTycService cloudTycService;
@Autowired @Autowired
private ScheduledExecutorService scheduledExecutorService;
@Autowired
private CompanyContactRepository companyContactRepository; private CompanyContactRepository companyContactRepository;
@Autowired @Autowired
private CompanyCustomerRepository companyCustomerRepository; private CompanyCustomerRepository companyCustomerRepository;
@@ -210,7 +209,8 @@ public class OldVersionService {
*/ */
public void scheduledTasks(TaskProgressView<Task<?>> taskProgressView) { public void scheduledTasks(TaskProgressView<Task<?>> taskProgressView) {
// 15分钟运行一次合同合同任务 // 15分钟运行一次合同合同任务
scheduledExecutorService.scheduleAtFixedRate(() -> { ScheduledExecutorService executorService = Desktop.instance.getExecutorService();
executorService.scheduleAtFixedRate(() -> {
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("createSyncTask"); logger.debug("createSyncTask");
} }
@@ -220,16 +220,9 @@ public class OldVersionService {
return; return;
} }
Task<Object> vendorTask = new OldVersionSyncVendorTask(); Desktop.instance.getTaskMonitorCenter().registerTask(new OldVersionSyncVendorTask()).schedule(5, TimeUnit.SECONDS);
Task<Object> customerTask = new OldVersionSyncCustomerTask(); Desktop.instance.getTaskMonitorCenter().registerTask(new OldVersionSyncCustomerTask()).schedule(5, TimeUnit.SECONDS);
scheduledExecutorService.schedule(() -> {
vendorTask.run();
customerTask.run();
}, 5, TimeUnit.SECONDS);
Platform.runLater(() -> {
taskProgressView.getTasks().addAll(vendorTask, customerTask);
});
}, 3, TimeUnit.DAYS.toSeconds(1), TimeUnit.SECONDS); }, 3, TimeUnit.DAYS.toSeconds(1), TimeUnit.SECONDS);
} }

View File

@@ -1,13 +1,5 @@
package com.ecep.contract.manager.cloud.old; package com.ecep.contract.manager.cloud.old;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.contract.model.Contract;
import javafx.concurrent.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -16,10 +8,20 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.contract.model.Contract;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.Tasker;
/** /**
* *
*/ */
public class OldVersionSyncCustomerTask extends Task<Object> { public class OldVersionSyncCustomerTask extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(OldVersionSyncCustomerTask.class); private static final Logger logger = LoggerFactory.getLogger(OldVersionSyncCustomerTask.class);
private final OldVersionService service = SpringApp.getBean(OldVersionService.class); private final OldVersionService service = SpringApp.getBean(OldVersionService.class);
@@ -40,7 +42,7 @@ public class OldVersionSyncCustomerTask extends Task<Object> {
} }
@Override @Override
protected Object call() throws Exception { protected Object execute(MessageHolder holder) throws Exception {
updateTitle("老版本-同步客户数据"); updateTitle("老版本-同步客户数据");
basePath = companyService.getCustomerBasePath(); basePath = companyService.getCustomerBasePath();
List<Runnable> runnable = Arrays.asList(this::loadOldNames, this::loadContacts, this::syncCustomers, this::syncContracts); List<Runnable> runnable = Arrays.asList(this::loadOldNames, this::loadContacts, this::syncCustomers, this::syncContracts);
@@ -122,4 +124,5 @@ public class OldVersionSyncCustomerTask extends Task<Object> {
} }
} }
} }

View File

@@ -1,13 +1,5 @@
package com.ecep.contract.manager.cloud.old; package com.ecep.contract.manager.cloud.old;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.contract.model.Contract;
import javafx.concurrent.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File; import java.io.File;
import java.util.Arrays; import java.util.Arrays;
import java.util.List; import java.util.List;
@@ -16,7 +8,17 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
public class OldVersionSyncVendorTask extends Task<Object> { import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.ecep.contract.manager.SpringApp;
import com.ecep.contract.manager.ds.company.model.Company;
import com.ecep.contract.manager.ds.company.service.CompanyService;
import com.ecep.contract.manager.ds.contract.model.Contract;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.ui.Tasker;
public class OldVersionSyncVendorTask extends Tasker<Object> {
private static final Logger logger = LoggerFactory.getLogger(OldVersionSyncVendorTask.class); private static final Logger logger = LoggerFactory.getLogger(OldVersionSyncVendorTask.class);
private final OldVersionService service = SpringApp.getBean(OldVersionService.class); private final OldVersionService service = SpringApp.getBean(OldVersionService.class);
@@ -35,12 +37,11 @@ public class OldVersionSyncVendorTask extends Task<Object> {
super.updateTitle(titlePrefix + title); super.updateTitle(titlePrefix + title);
} }
@Override @Override
protected Object call() throws Exception { protected Object execute(MessageHolder holder) throws Exception {
basePath = companyService.getVendorBasePath(); basePath = companyService.getVendorBasePath();
List<Runnable> runnable = Arrays.asList(this::loadOldNames, this::loadContacts, this::syncVendors,
List<Runnable> runnable = Arrays.asList(this::loadOldNames, this::loadContacts, this::syncVendors, this::syncContracts); this::syncContracts);
for (int i = 0; i < runnable.size(); i++) { for (int i = 0; i < runnable.size(); i++) {
titlePrefix = "老版本-同步供应商数据-" + (i + 1) + "/" + runnable.size() + "-"; titlePrefix = "老版本-同步供应商数据-" + (i + 1) + "/" + runnable.size() + "-";
try { try {
@@ -116,4 +117,5 @@ public class OldVersionSyncVendorTask extends Task<Object> {
}); });
} }
} }
} }

View File

@@ -1,6 +1,6 @@
package com.ecep.contract.manager.cloud.rk; package com.ecep.contract.manager.cloud.rk;
import com.ecep.contract.manager.Desktop;
import com.ecep.contract.manager.cloud.CloudInfo; import com.ecep.contract.manager.cloud.CloudInfo;
import com.ecep.contract.manager.ds.company.BlackReasonType; import com.ecep.contract.manager.ds.company.BlackReasonType;
import com.ecep.contract.manager.ds.company.CompanyFileUtils; import com.ecep.contract.manager.ds.company.CompanyFileUtils;
@@ -88,7 +88,6 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
return MyStringUtils.toLong(string, DEFAULT_SYNC_ELAPSE); return MyStringUtils.toLong(string, DEFAULT_SYNC_ELAPSE);
} }
@Data @Data
@JsonIgnoreProperties(ignoreUnknown = true) @JsonIgnoreProperties(ignoreUnknown = true)
public static class EntInfo { public static class EntInfo {
@@ -110,8 +109,6 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
private CompanyOldNameRepository companyOldNameRepository; private CompanyOldNameRepository companyOldNameRepository;
@Autowired @Autowired
private CompanyBlackReasonRepository companyBlackReasonRepository; private CompanyBlackReasonRepository companyBlackReasonRepository;
@Autowired
private ScheduledExecutorService scheduledExecutorService;
@Cacheable(key = "#p0") @Cacheable(key = "#p0")
public CloudRk findById(Integer id) { public CloudRk findById(Integer id) {
@@ -133,8 +130,7 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
builder.like(company.get("name"), "%" + searchText + "%"), builder.like(company.get("name"), "%" + searchText + "%"),
builder.like(company.get("shortName"), "%" + searchText + "%"), builder.like(company.get("shortName"), "%" + searchText + "%"),
builder.like(root.get("cloudId"), "%" + searchText + "%"), builder.like(root.get("cloudId"), "%" + searchText + "%"),
builder.like(root.get("description"), "%" + searchText + "%") builder.like(root.get("description"), "%" + searchText + "%"));
);
}; };
} }
@@ -142,8 +138,7 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
* 更新黑名单列表 * 更新黑名单列表
*/ */
public void updateBlackList( public void updateBlackList(
Company company, CloudRk cloudRk, BlackListUpdateContext context Company company, CloudRk cloudRk, BlackListUpdateContext context) throws IOException {
) throws IOException {
List<String> companyNames = new ArrayList<>(); List<String> companyNames = new ArrayList<>();
companyNames.add(company.getName()); companyNames.add(company.getName());
// fixed 平台API使用企业名称可能记录的是曾用名 // fixed 平台API使用企业名称可能记录的是曾用名
@@ -172,12 +167,14 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
try { try {
if (data.has("blackReason")) { if (data.has("blackReason")) {
for (JsonNode reason : data.get("blackReason")) { for (JsonNode reason : data.get("blackReason")) {
toCompanyBlackReasonList(company, BlackReasonType.BLACK, reason, dbReasons, reasonList, context.getObjectMapper()); toCompanyBlackReasonList(company, BlackReasonType.BLACK, reason, dbReasons,
reasonList, context.getObjectMapper());
} }
} }
if (data.has("greyReason")) { if (data.has("greyReason")) {
for (JsonNode reason : data.get("greyReason")) { for (JsonNode reason : data.get("greyReason")) {
toCompanyBlackReasonList(company, BlackReasonType.GRAY, reason, dbReasons, reasonList, context.getObjectMapper()); toCompanyBlackReasonList(company, BlackReasonType.GRAY, reason, dbReasons,
reasonList, context.getObjectMapper());
} }
} }
} catch (Exception ex) { } catch (Exception ex) {
@@ -214,11 +211,11 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
private void toCompanyBlackReasonList( private void toCompanyBlackReasonList(
Company company, BlackReasonType type, Company company, BlackReasonType type,
JsonNode reason, List<CompanyBlackReason> dbReasons, JsonNode reason, List<CompanyBlackReason> dbReasons,
List<CompanyBlackReason> reasonList, ObjectMapper objectMapper List<CompanyBlackReason> reasonList, ObjectMapper objectMapper) throws JsonMappingException {
) throws JsonMappingException {
ObjectNode object = (ObjectNode) reason; ObjectNode object = (ObjectNode) reason;
String key = "rk-" + object.remove("id").asText(); String key = "rk-" + object.remove("id").asText();
CompanyBlackReason cbr = dbReasons.stream().filter(r -> r.getKey().equals(key)).findAny().orElseGet(CompanyBlackReason::new); CompanyBlackReason cbr = dbReasons.stream().filter(r -> r.getKey().equals(key)).findAny()
.orElseGet(CompanyBlackReason::new);
objectMapper.updateValue(cbr, reason); objectMapper.updateValue(cbr, reason);
cbr.setCompany(company); cbr.setCompany(company);
cbr.setType(type); cbr.setType(type);
@@ -241,8 +238,7 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
* @return true * @return true
*/ */
public boolean checkBlackListUpdateElapse( public boolean checkBlackListUpdateElapse(
Company company, CloudRk cloudRk, BlackListUpdateContext context Company company, CloudRk cloudRk, BlackListUpdateContext context) {
) {
Instant start = cloudRk.getCloudBlackListUpdated(); Instant start = cloudRk.getCloudBlackListUpdated();
if (start == null) { if (start == null) {
return true; return true;
@@ -280,7 +276,8 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
} }
// 查询有 CloudId 的记录 // 查询有 CloudId 的记录
List<CloudRk> hasCouldIdList = list.stream().filter(v -> StringUtils.hasText(v.getCloudId())).collect(Collectors.toList()); List<CloudRk> hasCouldIdList = list.stream().filter(v -> StringUtils.hasText(v.getCloudId()))
.collect(Collectors.toList());
// 没有匹配到一条时 // 没有匹配到一条时
if (hasCouldIdList.isEmpty()) { if (hasCouldIdList.isEmpty()) {
// 保留第一条,其他删除 // 保留第一条,其他删除
@@ -299,7 +296,8 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
} }
// 查询有 CloudLatest 的记录 // 查询有 CloudLatest 的记录
List<CloudRk> hasLatestList = hasCouldIdList.stream().filter(v -> v.getCloudLatest() != null).collect(Collectors.toList()); List<CloudRk> hasLatestList = hasCouldIdList.stream().filter(v -> v.getCloudLatest() != null)
.collect(Collectors.toList());
// 没有匹配到一条时 // 没有匹配到一条时
if (hasLatestList.isEmpty()) { if (hasLatestList.isEmpty()) {
// 保留第一条,其他删除 // 保留第一条,其他删除
@@ -338,7 +336,6 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
cloudRKRepository.delete(entity); cloudRKRepository.delete(entity);
} }
/** /**
* 返回 在 {@link #getSyncElapse()} 毫秒前,更新的 * 返回 在 {@link #getSyncElapse()} 毫秒前,更新的
* *
@@ -354,7 +351,7 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
/** /**
* 返回距离上次更新超过 SysConfigcloud.rk.black_list.elapse 秒的公司 * 返回距离上次更新超过 SysConfigcloud.rk.black_list.elapse 秒的公司
*/ */
// @Transactional // @Transactional
public List<CloudRk> findNeedUpdate() { public List<CloudRk> findNeedUpdate() {
Instant now = Instant.now(); Instant now = Instant.now();
long elapse = getSyncElapse(); long elapse = getSyncElapse();
@@ -368,26 +365,14 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
* @param taskProgressView 任务视图 * @param taskProgressView 任务视图
*/ */
public void scheduledTasks(TaskProgressView<Task<?>> taskProgressView) { public void scheduledTasks(TaskProgressView<Task<?>> taskProgressView) {
AtomicReference<Runnable> reference = new AtomicReference<>(); ScheduledExecutorService executorService = Desktop.instance.getExecutorService();
Runnable runnable = () -> { // 第一次延时1分钟启动
CloudRkSyncTask task = new CloudRkSyncTask(); executorService.schedule(() -> {
Platform.runLater(() -> taskProgressView.getTasks().add(task)); // 定时 30分钟 运行一次
// 延迟10秒 executorService.scheduleAtFixedRate(() -> {
task.delay(10, CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS, scheduledExecutorService)) Desktop.instance.getTaskMonitorCenter().registerTask(new CloudRkSyncTask()).submit();
.thenRun(() -> { }, 0, 30, TimeUnit.MINUTES);
try { }, 1, TimeUnit.MINUTES);
task.run();
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
// 30 分钟后再次运行
scheduledExecutorService.schedule(reference.get(), 30, TimeUnit.MINUTES);
}
);
};
reference.set(runnable);
// 第一次延时启动
scheduledExecutorService.schedule(runnable, 1, TimeUnit.MINUTES);
} }
@CacheEvict @CacheEvict
@@ -401,12 +386,10 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
} }
// TODO 这个可以无法更新缓存 // TODO 这个可以无法更新缓存
@Caching( @Caching(evict = {
evict = { @CacheEvict(key = "#p0.id"),
@CacheEvict(key = "#p0.id"), @CacheEvict(key = "#p1.id"),
@CacheEvict(key = "#p1.id"), })
}
)
public void resetTo(Company from, Company to) { public void resetTo(Company from, Company to) {
List<CloudRk> list = cloudRKRepository.findAllByCompanyId(from.getId()); List<CloudRk> list = cloudRKRepository.findAllByCompanyId(from.getId());
for (CloudRk item : list) { for (CloudRk item : list) {

View File

@@ -118,20 +118,20 @@ public class YongYouU8Service implements ViewModelService<CloudYu, CloudYuInfoVi
executorService.scheduleAtFixedRate(() -> { executorService.scheduleAtFixedRate(() -> {
ContractSyncTask task = new ContractSyncTask(); ContractSyncTask task = new ContractSyncTask();
MonitoredTask<Object> registerTask = Desktop.instance.getTaskMonitorCenter().registerTask(task); MonitoredTask<Object> registerTask = Desktop.instance.getTaskMonitorCenter().registerTask(task);
executorService.schedule(registerTask, 5, TimeUnit.SECONDS); registerTask.schedule(5, TimeUnit.SECONDS);
}, 3, TimeUnit.MINUTES.toSeconds(15), TimeUnit.SECONDS); }, 3, TimeUnit.MINUTES.toSeconds(15), TimeUnit.SECONDS);
executorService.scheduleAtFixedRate(() -> { executorService.scheduleAtFixedRate(() -> {
// 1小时运行一次同步供应商任务 // 1小时运行一次同步供应商任务
VendorSyncTask vendorTask = new VendorSyncTask(); VendorSyncTask vendorTask = new VendorSyncTask();
MonitoredTask<Object> registerVendorTask = Desktop.instance.getTaskMonitorCenter().registerTask(vendorTask); MonitoredTask<Object> registerVendorTask = Desktop.instance.getTaskMonitorCenter().registerTask(vendorTask);
executorService.schedule(registerVendorTask, 60, TimeUnit.SECONDS); registerVendorTask.schedule(60, TimeUnit.SECONDS);
// 1小时运行一次同步客户任务 // 1小时运行一次同步客户任务
CustomerSyncTask customerTask = new CustomerSyncTask(); CustomerSyncTask customerTask = new CustomerSyncTask();
MonitoredTask<Object> registerCustomerTask = Desktop.instance.getTaskMonitorCenter() MonitoredTask<Object> registerCustomerTask = Desktop.instance.getTaskMonitorCenter()
.registerTask(customerTask); .registerTask(customerTask);
executorService.schedule(registerCustomerTask, 60, TimeUnit.SECONDS); registerCustomerTask.schedule(60, TimeUnit.SECONDS);
}, 3, TimeUnit.HOURS.toSeconds(1), TimeUnit.SECONDS); }, 3, TimeUnit.HOURS.toSeconds(1), TimeUnit.SECONDS);

View File

@@ -17,6 +17,8 @@ import javax.sql.DataSource;
import static com.ecep.contract.manager.AppV2.*; import static com.ecep.contract.manager.AppV2.*;
import java.util.Map;
@Configuration @Configuration
@EnableJpaRepositories(bootstrapMode = BootstrapMode.LAZY) @EnableJpaRepositories(bootstrapMode = BootstrapMode.LAZY)
public class DsRepositoriesConfig { public class DsRepositoriesConfig {
@@ -41,7 +43,6 @@ public class DsRepositoriesConfig {
logger.debug("db server url:{},user:{}", url, username); logger.debug("db server url:{},user:{}", url, username);
} }
return DataSourceBuilder.create() return DataSourceBuilder.create()
.type(HikariDataSource.class) .type(HikariDataSource.class)
.url(url) .url(url)

View File

@@ -1,5 +1,6 @@
package com.ecep.contract.manager.ui.task; package com.ecep.contract.manager.ui.task;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture; import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicBoolean;
@@ -46,7 +47,7 @@ public class MonitoredTask<T> implements Runnable {
private final ObjectProperty<Throwable> exception = new SimpleObjectProperty<>(this, "exception"); private final ObjectProperty<Throwable> exception = new SimpleObjectProperty<>(this, "exception");
private final ObjectProperty<Runnable> succeededProperty = new SimpleObjectProperty<>(); private final ObjectProperty<Runnable> succeededProperty = new SimpleObjectProperty<>();
private final ObjectProperty<Runnable> failedProperty = new SimpleObjectProperty<>(); private final ObjectProperty<Runnable> failedProperty = new SimpleObjectProperty<>();
private final ObjectProperty<Runnable> cancelledProperty = new SimpleObjectProperty<>(); private final ObjectProperty<Runnable> cancelledHandler = new SimpleObjectProperty<>();
private final AtomicBoolean timeoutHandled = new AtomicBoolean(false); private final AtomicBoolean timeoutHandled = new AtomicBoolean(false);
public MonitoredTask(Tasker<T> delegate, String taskId) { public MonitoredTask(Tasker<T> delegate, String taskId) {
@@ -85,15 +86,16 @@ public class MonitoredTask<T> implements Runnable {
private void stateChanged(ObservableValue<? extends Worker.State> observable, Worker.State oldValue, private void stateChanged(ObservableValue<? extends Worker.State> observable, Worker.State oldValue,
Worker.State newValue) { Worker.State newValue) {
switch (newValue) { switch (newValue) {
case RUNNING: case RUNNING: {
if (stateProperty().get() != TaskStatus.RUNNING) {
if (logger.isWarnEnabled()) {
logger.warn("任务{} 的 delegate 状态从 {} 变更为 {} 时, monitor的状态 {} 不是 RUNNING", taskId, oldValue,
newValue, stateProperty().get());
}
}
stateProperty().set(TaskStatus.RUNNING); stateProperty().set(TaskStatus.RUNNING);
break; break;
case SUCCEEDED: }
stateProperty().set(TaskStatus.SUCCEEDED);
break;
case FAILED:
stateProperty().set(TaskStatus.FAILED);
break;
case CANCELLED: case CANCELLED:
stateProperty().set(TaskStatus.CANCELLED); stateProperty().set(TaskStatus.CANCELLED);
cancelledProperty().get().run(); cancelledProperty().get().run();
@@ -103,6 +105,40 @@ public class MonitoredTask<T> implements Runnable {
} }
} }
@Override
public void run() {
if (logger.isDebugEnabled()) {
logger.debug("任务 {} 开始执行", taskId);
}
stateProperty().set(TaskStatus.RUNNING);
try {
call();
if (logger.isDebugEnabled()) {
logger.debug("任务 {} 执行完成", taskId);
}
} catch (Throwable e) {
exceptionProperty().set(e);
if (logger.isDebugEnabled()) {
logger.debug("任务 {} 执行异常", taskId, e);
}
} finally {
try {
if (exceptionProperty().get() == null) {
stateProperty().set(TaskStatus.SUCCEEDED);
succeededProperty().get().run();
} else {
stateProperty().set(TaskStatus.FAILED);
failedProperty().get().run();
}
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("任务 {} 回调执行异常", taskId, e);
}
}
}
}
public StringProperty titleProperty() { public StringProperty titleProperty() {
return title; return title;
} }
@@ -136,41 +172,7 @@ public class MonitoredTask<T> implements Runnable {
} }
public ObjectProperty<Runnable> cancelledProperty() { public ObjectProperty<Runnable> cancelledProperty() {
return cancelledProperty; return cancelledHandler;
}
@Override
public void run() {
if (logger.isDebugEnabled()) {
logger.debug("任务 {} 开始执行", taskId);
}
stateProperty().set(TaskStatus.SCHEDULED);
try {
call();
if (logger.isDebugEnabled()) {
logger.debug("任务 {} 执行完成", taskId);
}
} catch (Throwable e) {
exceptionProperty().set(e);
if (logger.isDebugEnabled()) {
logger.debug("任务 {} 执行异常", taskId, e);
}
} finally {
try {
if (exceptionProperty().get() == null) {
stateProperty().set(TaskStatus.SUCCEEDED);
succeededProperty().get().run();
} else {
failedProperty().get().run();
}
} catch (Exception e) {
if (logger.isDebugEnabled()) {
logger.debug("任务 {} 回调执行异常", taskId, e);
}
}
}
} }
protected T call() throws Exception { protected T call() throws Exception {
@@ -194,7 +196,7 @@ public class MonitoredTask<T> implements Runnable {
* 设置超时监控 * 设置超时监控
*/ */
private void setupTimeoutMonitor() { private void setupTimeoutMonitor() {
timeoutExecutor = Desktop.instance.getExecutorService().schedule(() -> { timeoutExecutor = getExecutorService().schedule(() -> {
if (isRunning() && timeoutHandled.compareAndSet(false, true)) { if (isRunning() && timeoutHandled.compareAndSet(false, true)) {
updateMessage("任务执行超时,正在取消..."); updateMessage("任务执行超时,正在取消...");
stateProperty().set(TaskStatus.TIMED_OUT); stateProperty().set(TaskStatus.TIMED_OUT);
@@ -203,6 +205,16 @@ public class MonitoredTask<T> implements Runnable {
}, timeoutSeconds, TimeUnit.SECONDS); }, timeoutSeconds, TimeUnit.SECONDS);
} }
public void submit() {
getExecutorService().submit(this);
}
public ScheduledFuture<?> schedule(long delay, TimeUnit unit) {
ScheduledFuture<?> schedule = getExecutorService().schedule(this, delay, unit);
stateProperty().set(TaskStatus.DELAYED);
return schedule;
}
private void updateMessage(String string) { private void updateMessage(String string) {
messageProperty().set(string); messageProperty().set(string);
} }
@@ -247,10 +259,15 @@ public class MonitoredTask<T> implements Runnable {
} }
public void setOnCancelled(Runnable value) { public void setOnCancelled(Runnable value) {
cancelledProperty.set(value); cancelledHandler.set(value);
} }
public void setOnRunning(EventHandler<WorkerStateEvent> value) { public void setOnRunning(EventHandler<WorkerStateEvent> value) {
delegate.setOnRunning(value); delegate.setOnRunning(value);
} }
ScheduledExecutorService getExecutorService() {
return Desktop.instance.getExecutorService();
}
} }

View File

@@ -36,7 +36,6 @@ import javafx.stage.WindowEvent;
/** /**
* 任务监控界面控制器 * 任务监控界面控制器
*/ */
@Lazy @Lazy
@Scope("prototype") @Scope("prototype")
@Component @Component
@@ -144,20 +143,7 @@ public class TaskMonitorViewController extends BaseController {
return row; return row;
}); });
// 更新按钮状态
// updateButtonStates();
cancelTaskButton.disableProperty().bind(activeTasksTable.getSelectionModel().selectedItemProperty().isNull()); cancelTaskButton.disableProperty().bind(activeTasksTable.getSelectionModel().selectedItemProperty().isNull());
// activeTasksTable.getSelectionModel().selectedItemProperty()
// .addListener((obs, oldVal, newVal) -> updateButtonStates());
}
/**
* 更新按钮状态
*/
private void updateButtonStates() {
cancelTaskButton.setDisable(activeTasksTable.getSelectionModel().getSelectedItem() == null);
} }
/** /**
@@ -197,6 +183,7 @@ public class TaskMonitorViewController extends BaseController {
alert.setHeaderText(history.getTitle()); alert.setHeaderText(history.getTitle());
ScrollPane scrollPane = new ScrollPane(); ScrollPane scrollPane = new ScrollPane();
scrollPane.setPrefHeight(300);
VBox vBox = new VBox(); VBox vBox = new VBox();
Label taskIdLabel = new Label("任务ID: " + history.getTaskId()); Label taskIdLabel = new Label("任务ID: " + history.getTaskId());

View File

@@ -5,9 +5,9 @@ package com.ecep.contract.manager.ui.task;
*/ */
public enum TaskStatus { public enum TaskStatus {
/** /**
* 进入调度,等待执行 * 进入等待延时队列,等待执行
*/ */
UN_SCHEDULED("未调度"), DELAYED("延时"),
/** /**
* 已调度 * 已调度
*/ */

View File

@@ -27,4 +27,8 @@ spring.data.jpa.repositories.enabled=true
spring.lifecycle.performance.enabled=true spring.lifecycle.performance.enabled=true
# my.downloadsPath = C:\\Users\\SQQ\\Downloads\\ # my.downloadsPath = C:\\Users\\SQQ\\Downloads\\
logging.level.org.hibernate.tool.hbm2ddl=DEBUG logging.level.org.hibernate.tool.hbm2ddl=DEBUG
# 在application.properties中添加
logging.level.org.springframework.boot.context.metrics.buffering=DEBUG
logging.level.com.ecep.contract.manager.SpringApp=DEBUG

View File

@@ -1,55 +1,63 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.Button?> <?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?> <?import javafx.scene.control.Tab?>
<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.TableColumn?> <?import javafx.scene.control.TableColumn?>
<?import javafx.scene.control.TableView?> <?import javafx.scene.control.TableView?>
<?import javafx.scene.layout.HBox?> <?import javafx.scene.control.ToolBar?>
<?import javafx.scene.layout.VBox?> <?import javafx.scene.layout.VBox?>
<VBox fx:id="root" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ecep.contract.manager.ui.task.TaskMonitorViewController">
<padding> <TabPane minHeight="400.0" minWidth="500.0" tabMinWidth="70.0" xmlns="http://javafx.com/javafx/22" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.ecep.contract.manager.ui.task.TaskMonitorViewController">
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" /> <tabs>
</padding> <Tab closable="false" text="活动任务">
<VBox spacing="10.0" VBox.vgrow="ALWAYS"> <content>
<!-- 活动任务区域 --> <VBox>
<VBox spacing="5.0"> <children>
<Label text="活动任务" /> <ToolBar prefHeight="40.0" prefWidth="200.0">
<TableView fx:id="activeTasksTable" VBox.vgrow="ALWAYS"> <items>
<columns> <Button fx:id="cancelTaskButton" text="取消选中任务" />
<TableColumn fx:id="activeTaskIdColumn" prefWidth="150.0" text="任务ID" /> </items>
<TableColumn fx:id="activeTaskTitleColumn" prefWidth="200.0" text="任务标题" /> </ToolBar>
<TableColumn fx:id="activeTaskProgressColumn" prefWidth="150.0" text="进度" /> <TableView fx:id="activeTasksTable">
<TableColumn fx:id="activeTaskStatusColumn" prefWidth="100.0" text="状态" /> <columns>
</columns> <TableColumn fx:id="activeTaskIdColumn" prefWidth="150.0" text="任务ID" />
<columnResizePolicy> <TableColumn fx:id="activeTaskTitleColumn" prefWidth="200.0" text="任务标题" />
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> <TableColumn fx:id="activeTaskProgressColumn" prefWidth="150.0" text="进度" />
</columnResizePolicy> <TableColumn fx:id="activeTaskStatusColumn" prefWidth="100.0" text="状态" />
</TableView> </columns>
<HBox alignment="CENTER_RIGHT"> <columnResizePolicy>
<Button fx:id="cancelTaskButton" text="取消选中任务" /> <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</HBox> </columnResizePolicy>
</VBox> </TableView>
</children>
<!-- 历史任务区域 --> </VBox>
<VBox spacing="5.0" VBox.vgrow="ALWAYS"> </content>
<HBox> </Tab>
<Label text="任务历史" /> <Tab closable="false" text="任务历史">
<Button fx:id="clearHistoryButton" alignment="CENTER_RIGHT" text="清空历史" HBox.hgrow="ALWAYS" /> <content>
</HBox> <!-- 历史任务区域 -->
<VBox spacing="5.0">
<ToolBar prefHeight="40.0" prefWidth="200.0">
<items>
<Button fx:id="clearHistoryButton" alignment="CENTER_RIGHT" text="清空历史" />
</items>
</ToolBar>
<TableView fx:id="historyTasksTable" VBox.vgrow="ALWAYS"> <TableView fx:id="historyTasksTable" VBox.vgrow="ALWAYS">
<columns> <columns>
<TableColumn fx:id="historyTaskIdColumn" prefWidth="150.0" text="任务ID" /> <TableColumn fx:id="historyTaskIdColumn" prefWidth="150.0" text="任务ID" />
<TableColumn fx:id="historyTaskTitleColumn" prefWidth="200.0" text="任务标题" /> <TableColumn fx:id="historyTaskTitleColumn" prefWidth="200.0" text="任务标题" />
<TableColumn fx:id="historyTaskStatusColumn" prefWidth="100.0" text="状态" /> <TableColumn fx:id="historyTaskStatusColumn" prefWidth="100.0" text="状态" />
<TableColumn fx:id="historyTaskStartTimeColumn" prefWidth="150.0" text="开始时间" /> <TableColumn fx:id="historyTaskStartTimeColumn" prefWidth="150.0" text="开始时间" />
<TableColumn fx:id="historyTaskExecutionTimeColumn" prefWidth="100.0" text="执行耗时" /> <TableColumn fx:id="historyTaskExecutionTimeColumn" prefWidth="100.0" text="执行耗时" />
</columns> </columns>
<columnResizePolicy> <columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" /> <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy> </columnResizePolicy>
</TableView> </TableView>
</VBox> </VBox>
</VBox> </content>
</VBox> </Tab>
</tabs>
</TabPane>