feat:多机证书导入功能
This commit is contained in:
@@ -0,0 +1,141 @@
|
||||
package com.sunyard.task;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.*;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AsyncTaskExecutor {
|
||||
|
||||
private final ExecutorService taskExecutor;
|
||||
private final ScheduledExecutorService retryScheduler;
|
||||
|
||||
public AsyncTaskExecutor(int taskThreads, int retryThreads) {
|
||||
this.taskExecutor = Executors.newFixedThreadPool(taskThreads);
|
||||
this.retryScheduler = Executors.newScheduledThreadPool(retryThreads);
|
||||
}
|
||||
|
||||
// 默认配置构造函数
|
||||
public AsyncTaskExecutor() {
|
||||
this(4, 2);
|
||||
}
|
||||
|
||||
public List<TaskOutcome<String>> execTasks(List<TaskContext<String>> taskContexts) {
|
||||
List<CompletableFuture<String>> futures =
|
||||
taskContexts.stream().map(this::retryWithDelay).collect(Collectors.toList());
|
||||
List<TaskOutcome<String>> taskOutcomes = new ArrayList<>();
|
||||
taskContexts.forEach(task ->
|
||||
retryWithDelay(task).whenCompleteAsync((result, ex) -> {
|
||||
if (ex != null) {
|
||||
// 提取原始异常
|
||||
Throwable rootCause = ex instanceof CompletionException ? ex.getCause() : ex;
|
||||
taskOutcomes.add(new TaskOutcome<>(task, rootCause));
|
||||
} else {
|
||||
taskOutcomes.add(new TaskOutcome<>(task, result));
|
||||
}
|
||||
}));
|
||||
return taskOutcomes;
|
||||
}
|
||||
|
||||
public List<TaskOutcome<String>> execBatchTasks(List<TaskContext<String>> taskContexts) {
|
||||
// 转换每个Future为明确的TaskOutcome类型
|
||||
List<CompletableFuture<TaskOutcome<String>>> futures = taskContexts.stream()
|
||||
.map(task ->
|
||||
retryWithDelay(task)
|
||||
.<TaskOutcome<String>>handle((result, ex) -> {
|
||||
if (ex != null) {
|
||||
// 提取原始异常
|
||||
Throwable cause = ex instanceof CompletionException ? ex.getCause() : ex;
|
||||
return new TaskOutcome<>(task, cause);
|
||||
} else {
|
||||
return new TaskOutcome<>(task, result);
|
||||
}
|
||||
})
|
||||
)
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// 等待所有任务完成
|
||||
CompletableFuture<Void> allFutures = CompletableFuture.allOf(
|
||||
futures.toArray(new CompletableFuture[0])
|
||||
);
|
||||
|
||||
// 收集处理结果
|
||||
return allFutures.thenApply(v ->
|
||||
futures.stream()
|
||||
.map(CompletableFuture::join)
|
||||
.collect(Collectors.toList())
|
||||
).join();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 带延迟的重试逻辑
|
||||
*/
|
||||
private <T> CompletableFuture<T> retryWithDelay(TaskContext<T> context) {
|
||||
return CompletableFuture.supplyAsync(context.getTask(), taskExecutor)
|
||||
.handleAsync((result, ex) -> {
|
||||
if (ex == null) {
|
||||
return CompletableFuture.completedFuture(result);
|
||||
} else {
|
||||
return handleRetry(context, ex);
|
||||
}
|
||||
}, taskExecutor)
|
||||
.thenCompose(f -> f);
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* 处理重试逻辑
|
||||
*/
|
||||
private <T> CompletableFuture<T> handleRetry(TaskContext<T> context, Throwable ex) {
|
||||
if (context.canRetry()) {
|
||||
context.decreaseRetry();
|
||||
System.out.printf("[重试调度] ID: %s | 延迟: %ss | 剩余重试: %d | 错误: %s%n",
|
||||
context.getTaskId(),
|
||||
context.getRetryDelay().getSeconds(),
|
||||
context.getRetriesLeft(),
|
||||
ex.getCause().getMessage());
|
||||
|
||||
// 创建延迟重试的Future
|
||||
CompletableFuture<T> delayedRetry = new CompletableFuture<>();
|
||||
retryScheduler.schedule(() -> {
|
||||
retryWithDelay(context).whenComplete((retryResult, retryEx) -> {
|
||||
if (retryEx != null) {
|
||||
delayedRetry.completeExceptionally(retryEx);
|
||||
} else {
|
||||
delayedRetry.complete(retryResult);
|
||||
}
|
||||
});
|
||||
}, context.getRetryDelay().toMillis(), TimeUnit.MILLISECONDS);
|
||||
|
||||
return delayedRetry;
|
||||
} else {
|
||||
// 重试耗尽,传递原始异常
|
||||
CompletableFuture<T> failed = new CompletableFuture<>();
|
||||
failed.completeExceptionally(ex);
|
||||
return failed;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 关闭线程池
|
||||
*/
|
||||
public void shutdown() {
|
||||
taskExecutor.shutdown();
|
||||
retryScheduler.shutdown();
|
||||
try {
|
||||
if (!taskExecutor.awaitTermination(1, TimeUnit.SECONDS)) {
|
||||
taskExecutor.shutdownNow();
|
||||
}
|
||||
if (!retryScheduler.awaitTermination(1, TimeUnit.SECONDS)) {
|
||||
retryScheduler.shutdownNow();
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package com.sunyard.task;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class TaskContext<T> {
|
||||
private final String taskId; // 唯一任务ID
|
||||
private final Supplier<T> task; // 原始任务逻辑
|
||||
private int retriesLeft; // 剩余重试次数
|
||||
private final Duration retryDelay; // 重试延迟
|
||||
|
||||
private final String address;
|
||||
|
||||
public TaskContext(Supplier<T> task, int maxRetries, Duration retryDelay, String address) {
|
||||
this.taskId = UUID.randomUUID().toString();
|
||||
this.task = task;
|
||||
this.retriesLeft = maxRetries;
|
||||
this.retryDelay = retryDelay;
|
||||
this.address = address;
|
||||
}
|
||||
|
||||
public String getAddress() {
|
||||
return address;
|
||||
}
|
||||
|
||||
public String getTaskId() {
|
||||
return taskId;
|
||||
}
|
||||
|
||||
public Supplier<T> getTask() {
|
||||
return task;
|
||||
}
|
||||
|
||||
public int getRetriesLeft() {
|
||||
return retriesLeft;
|
||||
}
|
||||
|
||||
public boolean canRetry() {
|
||||
return retriesLeft > 0;
|
||||
}
|
||||
|
||||
public void decreaseRetry() {
|
||||
retriesLeft--;
|
||||
}
|
||||
|
||||
public Duration getRetryDelay() {
|
||||
return retryDelay;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
package com.sunyard.task;
|
||||
|
||||
public class TaskOutcome<T> {
|
||||
private final TaskContext<T> context;
|
||||
private final T result;
|
||||
private final Throwable error;
|
||||
|
||||
public TaskOutcome(TaskContext<T> context, T result) {
|
||||
this.context = context;
|
||||
this.result = result;
|
||||
this.error = null;
|
||||
}
|
||||
|
||||
public TaskOutcome(TaskContext<T> context, Throwable error) {
|
||||
this.context = context;
|
||||
this.result = null;
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public boolean isSuccess() {
|
||||
return error == null;
|
||||
}
|
||||
|
||||
public TaskContext<T> getContext() {
|
||||
return context;
|
||||
}
|
||||
|
||||
public T getResult() {
|
||||
return result;
|
||||
}
|
||||
|
||||
public Throwable getError() {
|
||||
return error;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user