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

View File

@@ -1,18 +1,16 @@
package com.ecep.contract.manager;
import com.ecep.contract.manager.cloud.CloudRepositoriesConfig;
import com.ecep.contract.manager.ds.DsRepositoriesConfig;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.util.MyDateTimeUtils;
import com.ecep.contract.manager.util.UITools;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
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;
import java.time.Duration;
import java.time.Instant;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.format.DateTimeFormatter;
import java.util.Locale;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ScheduledExecutorService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.EnableScheduling;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.List;
import java.util.Locale;
import java.util.Properties;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executors;
import java.util.concurrent.FutureTask;
import java.util.concurrent.ScheduledExecutorService;
import com.ecep.contract.manager.cloud.CloudRepositoriesConfig;
import com.ecep.contract.manager.ds.DsRepositoriesConfig;
import com.ecep.contract.manager.ui.MessageHolder;
import com.ecep.contract.manager.util.MyDateTimeUtils;
import com.ecep.contract.manager.util.UITools;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.fasterxml.jackson.datatype.jsr310.deser.LocalDateDeserializer;
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
@EnableAsync
@EnableCaching
@@ -97,7 +99,6 @@ public class SpringApp {
}
});
startup.start("");
context = application.run();
logger.debug("SpringApp.launch application.run().");
@@ -178,7 +179,8 @@ public class SpringApp {
}
@Override
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext, ConfigurableEnvironment environment) {
public void environmentPrepared(ConfigurableBootstrapContext bootstrapContext,
ConfigurableEnvironment environment) {
logger.debug("Desktop.environmentPrepared");
debug("初始化 Environment 中,请稍后...");
}
@@ -195,7 +197,6 @@ public class SpringApp {
debug("Spring Application Context 初始化完毕,请稍后...");
}
@Override
public void started(ConfigurableApplicationContext context, Duration timeTaken) {
logger.debug("Desktop.started");
@@ -231,7 +232,7 @@ public class SpringApp {
@Bean
public CacheManager cacheManager() {
// return new ConcurrentMapCacheManager("myCache");
// return new ConcurrentMapCacheManager("myCache");
CaffeineCacheManager cacheManager = new CaffeineCacheManager();
cacheManager.setAsyncCacheMode(true);
return cacheManager;
@@ -242,10 +243,12 @@ public class SpringApp {
ObjectMapper objectMapper = new ObjectMapper();
JavaTimeModule javaTimeModule = new JavaTimeModule();
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.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));
objectMapper.registerModule(javaTimeModule);
return objectMapper;
@@ -253,7 +256,7 @@ public class SpringApp {
@Bean
public ScheduledExecutorService scheduledExecutorService() {
return Executors.newScheduledThreadPool(3);
return Desktop.instance.getExecutorService();
}
}

View File

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

View File

@@ -1,13 +1,5 @@
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.util.Arrays;
import java.util.List;
@@ -16,10 +8,20 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
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 final OldVersionService service = SpringApp.getBean(OldVersionService.class);
@@ -40,7 +42,7 @@ public class OldVersionSyncCustomerTask extends Task<Object> {
}
@Override
protected Object call() throws Exception {
protected Object execute(MessageHolder holder) throws Exception {
updateTitle("老版本-同步客户数据");
basePath = companyService.getCustomerBasePath();
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;
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.util.Arrays;
import java.util.List;
@@ -16,7 +8,17 @@ import java.util.concurrent.atomic.AtomicInteger;
import java.util.stream.Collectors;
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 final OldVersionService service = SpringApp.getBean(OldVersionService.class);
@@ -35,12 +37,11 @@ public class OldVersionSyncVendorTask extends Task<Object> {
super.updateTitle(titlePrefix + title);
}
@Override
protected Object call() throws Exception {
protected Object execute(MessageHolder holder) throws Exception {
basePath = companyService.getVendorBasePath();
List<Runnable> runnable = Arrays.asList(this::loadOldNames, this::loadContacts, this::syncVendors, this::syncContracts);
List<Runnable> runnable = Arrays.asList(this::loadOldNames, this::loadContacts, this::syncVendors,
this::syncContracts);
for (int i = 0; i < runnable.size(); i++) {
titlePrefix = "老版本-同步供应商数据-" + (i + 1) + "/" + runnable.size() + "-";
try {
@@ -116,4 +117,5 @@ public class OldVersionSyncVendorTask extends Task<Object> {
});
}
}
}

View File

@@ -1,6 +1,6 @@
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.ds.company.BlackReasonType;
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);
}
@Data
@JsonIgnoreProperties(ignoreUnknown = true)
public static class EntInfo {
@@ -110,8 +109,6 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
private CompanyOldNameRepository companyOldNameRepository;
@Autowired
private CompanyBlackReasonRepository companyBlackReasonRepository;
@Autowired
private ScheduledExecutorService scheduledExecutorService;
@Cacheable(key = "#p0")
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("shortName"), "%" + 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(
Company company, CloudRk cloudRk, BlackListUpdateContext context
) throws IOException {
Company company, CloudRk cloudRk, BlackListUpdateContext context) throws IOException {
List<String> companyNames = new ArrayList<>();
companyNames.add(company.getName());
// fixed 平台API使用企业名称可能记录的是曾用名
@@ -172,12 +167,14 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
try {
if (data.has("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")) {
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) {
@@ -214,11 +211,11 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
private void toCompanyBlackReasonList(
Company company, BlackReasonType type,
JsonNode reason, List<CompanyBlackReason> dbReasons,
List<CompanyBlackReason> reasonList, ObjectMapper objectMapper
) throws JsonMappingException {
List<CompanyBlackReason> reasonList, ObjectMapper objectMapper) throws JsonMappingException {
ObjectNode object = (ObjectNode) reason;
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);
cbr.setCompany(company);
cbr.setType(type);
@@ -241,8 +238,7 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
* @return true
*/
public boolean checkBlackListUpdateElapse(
Company company, CloudRk cloudRk, BlackListUpdateContext context
) {
Company company, CloudRk cloudRk, BlackListUpdateContext context) {
Instant start = cloudRk.getCloudBlackListUpdated();
if (start == null) {
return true;
@@ -280,7 +276,8 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
}
// 查询有 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()) {
// 保留第一条,其他删除
@@ -299,7 +296,8 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
}
// 查询有 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()) {
// 保留第一条,其他删除
@@ -338,7 +336,6 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
cloudRKRepository.delete(entity);
}
/**
* 返回 在 {@link #getSyncElapse()} 毫秒前,更新的
*
@@ -354,7 +351,7 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
/**
* 返回距离上次更新超过 SysConfigcloud.rk.black_list.elapse 秒的公司
*/
// @Transactional
// @Transactional
public List<CloudRk> findNeedUpdate() {
Instant now = Instant.now();
long elapse = getSyncElapse();
@@ -368,26 +365,14 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
* @param taskProgressView 任务视图
*/
public void scheduledTasks(TaskProgressView<Task<?>> taskProgressView) {
AtomicReference<Runnable> reference = new AtomicReference<>();
Runnable runnable = () -> {
CloudRkSyncTask task = new CloudRkSyncTask();
Platform.runLater(() -> taskProgressView.getTasks().add(task));
// 延迟10秒
task.delay(10, CompletableFuture.delayedExecutor(1, TimeUnit.SECONDS, scheduledExecutorService))
.thenRun(() -> {
try {
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);
ScheduledExecutorService executorService = Desktop.instance.getExecutorService();
// 第一次延时1分钟启动
executorService.schedule(() -> {
// 定时 30分钟 运行一次
executorService.scheduleAtFixedRate(() -> {
Desktop.instance.getTaskMonitorCenter().registerTask(new CloudRkSyncTask()).submit();
}, 0, 30, TimeUnit.MINUTES);
}, 1, TimeUnit.MINUTES);
}
@CacheEvict
@@ -401,12 +386,10 @@ public class CloudRkService implements ViewModelService<CloudRk, CloudRkInfoView
}
// TODO 这个可以无法更新缓存
@Caching(
evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "#p1.id"),
}
)
@Caching(evict = {
@CacheEvict(key = "#p0.id"),
@CacheEvict(key = "#p1.id"),
})
public void resetTo(Company from, Company to) {
List<CloudRk> list = cloudRKRepository.findAllByCompanyId(from.getId());
for (CloudRk item : list) {

View File

@@ -118,20 +118,20 @@ public class YongYouU8Service implements ViewModelService<CloudYu, CloudYuInfoVi
executorService.scheduleAtFixedRate(() -> {
ContractSyncTask task = new ContractSyncTask();
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);
executorService.scheduleAtFixedRate(() -> {
// 1小时运行一次同步供应商任务
VendorSyncTask vendorTask = new VendorSyncTask();
MonitoredTask<Object> registerVendorTask = Desktop.instance.getTaskMonitorCenter().registerTask(vendorTask);
executorService.schedule(registerVendorTask, 60, TimeUnit.SECONDS);
registerVendorTask.schedule(60, TimeUnit.SECONDS);
// 1小时运行一次同步客户任务
CustomerSyncTask customerTask = new CustomerSyncTask();
MonitoredTask<Object> registerCustomerTask = Desktop.instance.getTaskMonitorCenter()
.registerTask(customerTask);
executorService.schedule(registerCustomerTask, 60, TimeUnit.SECONDS);
registerCustomerTask.schedule(60, 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 java.util.Map;
@Configuration
@EnableJpaRepositories(bootstrapMode = BootstrapMode.LAZY)
public class DsRepositoriesConfig {
@@ -41,7 +43,6 @@ public class DsRepositoriesConfig {
logger.debug("db server url:{},user:{}", url, username);
}
return DataSourceBuilder.create()
.type(HikariDataSource.class)
.url(url)

View File

@@ -1,5 +1,6 @@
package com.ecep.contract.manager.ui.task;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.TimeUnit;
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<Runnable> succeededProperty = 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);
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,
Worker.State 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);
break;
case SUCCEEDED:
stateProperty().set(TaskStatus.SUCCEEDED);
break;
case FAILED:
stateProperty().set(TaskStatus.FAILED);
break;
}
case CANCELLED:
stateProperty().set(TaskStatus.CANCELLED);
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() {
return title;
}
@@ -136,41 +172,7 @@ public class MonitoredTask<T> implements Runnable {
}
public ObjectProperty<Runnable> cancelledProperty() {
return cancelledProperty;
}
@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);
}
}
}
return cancelledHandler;
}
protected T call() throws Exception {
@@ -194,7 +196,7 @@ public class MonitoredTask<T> implements Runnable {
* 设置超时监控
*/
private void setupTimeoutMonitor() {
timeoutExecutor = Desktop.instance.getExecutorService().schedule(() -> {
timeoutExecutor = getExecutorService().schedule(() -> {
if (isRunning() && timeoutHandled.compareAndSet(false, true)) {
updateMessage("任务执行超时,正在取消...");
stateProperty().set(TaskStatus.TIMED_OUT);
@@ -203,6 +205,16 @@ public class MonitoredTask<T> implements Runnable {
}, 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) {
messageProperty().set(string);
}
@@ -247,10 +259,15 @@ public class MonitoredTask<T> implements Runnable {
}
public void setOnCancelled(Runnable value) {
cancelledProperty.set(value);
cancelledHandler.set(value);
}
public void setOnRunning(EventHandler<WorkerStateEvent> value) {
delegate.setOnRunning(value);
}
ScheduledExecutorService getExecutorService() {
return Desktop.instance.getExecutorService();
}
}

View File

@@ -36,7 +36,6 @@ import javafx.stage.WindowEvent;
/**
* 任务监控界面控制器
*/
@Lazy
@Scope("prototype")
@Component
@@ -144,20 +143,7 @@ public class TaskMonitorViewController extends BaseController {
return row;
});
// 更新按钮状态
// updateButtonStates();
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());
ScrollPane scrollPane = new ScrollPane();
scrollPane.setPrefHeight(300);
VBox vBox = new VBox();
Label taskIdLabel = new Label("任务ID: " + history.getTaskId());

View File

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

View File

@@ -27,4 +27,8 @@ spring.data.jpa.repositories.enabled=true
spring.lifecycle.performance.enabled=true
# 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"?>
<?import javafx.geometry.Insets?>
<?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.TableView?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.ToolBar?>
<?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>
<Insets bottom="10.0" left="10.0" right="10.0" top="10.0" />
</padding>
<VBox spacing="10.0" VBox.vgrow="ALWAYS">
<!-- 活动任务区域 -->
<VBox spacing="5.0">
<Label text="活动任务" />
<TableView fx:id="activeTasksTable" VBox.vgrow="ALWAYS">
<columns>
<TableColumn fx:id="activeTaskIdColumn" prefWidth="150.0" text="任务ID" />
<TableColumn fx:id="activeTaskTitleColumn" prefWidth="200.0" text="任务标题" />
<TableColumn fx:id="activeTaskProgressColumn" prefWidth="150.0" text="进度" />
<TableColumn fx:id="activeTaskStatusColumn" prefWidth="100.0" text="状态" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
<HBox alignment="CENTER_RIGHT">
<Button fx:id="cancelTaskButton" text="取消选中任务" />
</HBox>
</VBox>
<!-- 历史任务区域 -->
<VBox spacing="5.0" VBox.vgrow="ALWAYS">
<HBox>
<Label text="任务历史" />
<Button fx:id="clearHistoryButton" alignment="CENTER_RIGHT" text="清空历史" HBox.hgrow="ALWAYS" />
</HBox>
<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">
<tabs>
<Tab closable="false" text="活动任务">
<content>
<VBox>
<children>
<ToolBar prefHeight="40.0" prefWidth="200.0">
<items>
<Button fx:id="cancelTaskButton" text="取消选中任务" />
</items>
</ToolBar>
<TableView fx:id="activeTasksTable">
<columns>
<TableColumn fx:id="activeTaskIdColumn" prefWidth="150.0" text="任务ID" />
<TableColumn fx:id="activeTaskTitleColumn" prefWidth="200.0" text="任务标题" />
<TableColumn fx:id="activeTaskProgressColumn" prefWidth="150.0" text="进度" />
<TableColumn fx:id="activeTaskStatusColumn" prefWidth="100.0" text="状态" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
</children>
</VBox>
</content>
</Tab>
<Tab closable="false" text="任务历史">
<content>
<!-- 历史任务区域 -->
<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">
<columns>
<TableColumn fx:id="historyTaskIdColumn" prefWidth="150.0" text="任务ID" />
<TableColumn fx:id="historyTaskTitleColumn" prefWidth="200.0" text="任务标题" />
<TableColumn fx:id="historyTaskStatusColumn" prefWidth="100.0" text="状态" />
<TableColumn fx:id="historyTaskStartTimeColumn" prefWidth="150.0" text="开始时间" />
<TableColumn fx:id="historyTaskExecutionTimeColumn" prefWidth="100.0" text="执行耗时" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
<columns>
<TableColumn fx:id="historyTaskIdColumn" prefWidth="150.0" text="任务ID" />
<TableColumn fx:id="historyTaskTitleColumn" prefWidth="200.0" text="任务标题" />
<TableColumn fx:id="historyTaskStatusColumn" prefWidth="100.0" text="状态" />
<TableColumn fx:id="historyTaskStartTimeColumn" prefWidth="150.0" text="开始时间" />
<TableColumn fx:id="historyTaskExecutionTimeColumn" prefWidth="100.0" text="执行耗时" />
</columns>
<columnResizePolicy>
<TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
</columnResizePolicy>
</TableView>
</VBox>
</VBox>
</VBox>
</VBox>
</content>
</Tab>
</tabs>
</TabPane>