mirror of
https://github.com/PowerJob/PowerJob.git
synced 2025-07-17 00:00:04 +08:00
feat: optimize Thread#stop usage
This commit is contained in:
parent
da04e4b048
commit
9f6d421ed2
@ -24,6 +24,12 @@ public class PowerJobDKey {
|
|||||||
public static final String IGNORED_NETWORK_INTERFACE_REGEX = "powerjob.network.interface.ignored";
|
public static final String IGNORED_NETWORK_INTERFACE_REGEX = "powerjob.network.interface.ignored";
|
||||||
|
|
||||||
public static final String WORKER_STATUS_CHECK_PERIOD = "powerjob.worker.status-check.normal.period";
|
public static final String WORKER_STATUS_CHECK_PERIOD = "powerjob.worker.status-check.normal.period";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* allowed PowerJob to invoke Thread#stop to kill a thread when PowerJob can't interrupt the thread
|
||||||
|
* <a href="https://stackoverflow.com/questions/16504140/thread-stop-deprecated">It's VERY dangerous</a>
|
||||||
|
*/
|
||||||
|
public static final String WORKER_ALLOWED_FORCE_STOP_THREAD = "powerjob.worker.allowed-force-stop-thread";
|
||||||
/**
|
/**
|
||||||
* ms
|
* ms
|
||||||
*/
|
*/
|
||||||
|
@ -5,7 +5,6 @@ import akka.pattern.Patterns;
|
|||||||
import com.google.common.collect.Maps;
|
import com.google.common.collect.Maps;
|
||||||
import lombok.extern.slf4j.Slf4j;
|
import lombok.extern.slf4j.Slf4j;
|
||||||
import org.springframework.beans.BeanUtils;
|
import org.springframework.beans.BeanUtils;
|
||||||
import tech.powerjob.common.RemoteConstant;
|
|
||||||
import tech.powerjob.common.enums.InstanceStatus;
|
import tech.powerjob.common.enums.InstanceStatus;
|
||||||
import tech.powerjob.common.model.InstanceDetail;
|
import tech.powerjob.common.model.InstanceDetail;
|
||||||
import tech.powerjob.common.request.ServerScheduleJobReq;
|
import tech.powerjob.common.request.ServerScheduleJobReq;
|
||||||
@ -113,7 +112,7 @@ public abstract class TaskTracker {
|
|||||||
serverActor.tell(response, null);
|
serverActor.tell(response, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void reportFinalStatus(ActorSelection serverActor, TaskTrackerReportInstanceStatusReq reportInstanceStatusReq) {
|
protected void reportFinalStatusThenDestory(ActorSelection serverActor, TaskTrackerReportInstanceStatusReq reportInstanceStatusReq) {
|
||||||
// 最终状态需要可靠上报
|
// 最终状态需要可靠上报
|
||||||
CompletionStage<Object> ask = Patterns.ask(serverActor, reportInstanceStatusReq, Duration.ofSeconds(15));
|
CompletionStage<Object> ask = Patterns.ask(serverActor, reportInstanceStatusReq, Duration.ofSeconds(15));
|
||||||
boolean serverAccepted = false;
|
boolean serverAccepted = false;
|
||||||
|
@ -236,6 +236,13 @@ public class LightTaskTracker extends TaskTracker {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
TODO:建议添加 锁 + 销毁判断,2种极限场景:
|
||||||
|
1. 先 processTask 调用,同时定时任务再次触发:理论上定时任务的处理栈上会抛出 InterruptException(虽然无实际功能的影响,但不够优雅,而且总归是问题)
|
||||||
|
2. 先定时任务触发,同时 processTask 调用:这种情况好像没太大的问题,重复上报2次
|
||||||
|
|
||||||
|
总而言之建议考虑理论情况下的"并行"场景,价格锁和入口状态判断增加代码健壮性
|
||||||
|
*/
|
||||||
private void checkAndReportStatus() {
|
private void checkAndReportStatus() {
|
||||||
String serverPath = AkkaUtils.getServerActorPath(workerRuntime.getServerDiscoveryService().getCurrentServerAddress());
|
String serverPath = AkkaUtils.getServerActorPath(workerRuntime.getServerDiscoveryService().getCurrentServerAddress());
|
||||||
ActorSelection serverActor = workerRuntime.getActorSystem().actorSelection(serverPath);
|
ActorSelection serverActor = workerRuntime.getActorSystem().actorSelection(serverPath);
|
||||||
@ -255,13 +262,13 @@ public class LightTaskTracker extends TaskTracker {
|
|||||||
final Thread workerThread = executeThread.get();
|
final Thread workerThread = executeThread.get();
|
||||||
if (!finished.get() && workerThread != null) {
|
if (!finished.get() && workerThread != null) {
|
||||||
// 未能成功打断任务,强制停止
|
// 未能成功打断任务,强制停止
|
||||||
log.warn("[TaskTracker-{}] task need stop,but fail to interrupt it,force stop thread {}", instanceId, executeThread.get().getName());
|
|
||||||
try {
|
try {
|
||||||
workerThread.stop();
|
if (tryForceStopThread(workerThread)) {
|
||||||
finished.set(true);
|
finished.set(true);
|
||||||
log.warn("[TaskTracker-{}] task need stop, force stop thread {} success!", instanceId, workerThread.getName());
|
log.warn("[TaskTracker-{}] task need stop, force stop thread {} success!", instanceId, workerThread.getName());
|
||||||
// 被终止的任务不需要上报状态
|
// 被终止的任务不需要上报状态
|
||||||
destroy();
|
destroy();
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("[TaskTracker-{}] task need stop,fail to stop thread {}", instanceId, workerThread.getName(), e);
|
log.warn("[TaskTracker-{}] task need stop,fail to stop thread {}", instanceId, workerThread.getName(), e);
|
||||||
}
|
}
|
||||||
@ -283,7 +290,7 @@ public class LightTaskTracker extends TaskTracker {
|
|||||||
reportInstanceStatusReq.setEndTime(taskEndTime);
|
reportInstanceStatusReq.setEndTime(taskEndTime);
|
||||||
// 微操一下,上报最终状态时重新设置下时间,并且增加一小段偏移,保证在并发上报运行中状态以及最终状态时,最终状态的上报时间晚于运行中的状态
|
// 微操一下,上报最终状态时重新设置下时间,并且增加一小段偏移,保证在并发上报运行中状态以及最终状态时,最终状态的上报时间晚于运行中的状态
|
||||||
reportInstanceStatusReq.setReportTime(System.currentTimeMillis() + 1);
|
reportInstanceStatusReq.setReportTime(System.currentTimeMillis() + 1);
|
||||||
reportFinalStatus(serverActor, reportInstanceStatusReq);
|
reportFinalStatusThenDestory(serverActor, reportInstanceStatusReq);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 未完成的任务,只需要上报状态
|
// 未完成的任务,只需要上报状态
|
||||||
@ -322,13 +329,13 @@ public class LightTaskTracker extends TaskTracker {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// 未能成功打断任务,强制终止
|
// 未能成功打断任务,强制终止
|
||||||
log.warn("[TaskTracker-{}] task timeout,but fail to interrupt it,force stop thread {}", instanceId, workerThread.getName());
|
|
||||||
try {
|
try {
|
||||||
workerThread.stop();
|
if (tryForceStopThread(workerThread)) {
|
||||||
finished.set(true);
|
finished.set(true);
|
||||||
taskEndTime = System.currentTimeMillis();
|
taskEndTime = System.currentTimeMillis();
|
||||||
result = new ProcessResult(false, SystemInstanceResult.INSTANCE_EXECUTE_TIMEOUT_FORCE_STOP);
|
result = new ProcessResult(false, SystemInstanceResult.INSTANCE_EXECUTE_TIMEOUT_FORCE_STOP);
|
||||||
log.warn("[TaskTracker-{}] task timeout, force stop thread {} success!", instanceId, workerThread.getName());
|
log.warn("[TaskTracker-{}] task timeout, force stop thread {} success!", instanceId, workerThread.getName());
|
||||||
|
}
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
log.warn("[TaskTracker-{}] task timeout,fail to stop thread {}", instanceId, workerThread.getName(), e);
|
log.warn("[TaskTracker-{}] task timeout,fail to stop thread {}", instanceId, workerThread.getName(), e);
|
||||||
}
|
}
|
||||||
@ -364,4 +371,29 @@ public class LightTaskTracker extends TaskTracker {
|
|||||||
return result.substring(0, maxLength).concat("...");
|
return result.substring(0, maxLength).concat("...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* try force stop thread
|
||||||
|
* @param thread thread
|
||||||
|
* @return stop result
|
||||||
|
*/
|
||||||
|
private boolean tryForceStopThread(Thread thread) {
|
||||||
|
|
||||||
|
String threadName = thread.getName();
|
||||||
|
|
||||||
|
String allowStopThread = System.getProperty(PowerJobDKey.WORKER_ALLOWED_FORCE_STOP_THREAD);
|
||||||
|
if (!StringUtils.equalsIgnoreCase(allowStopThread, Boolean.TRUE.toString())) {
|
||||||
|
log.warn("[TaskTracker-{}] PowerJob not allowed to force stop a thread by config", instanceId);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
log.warn("[TaskTracker-{}] fail to interrupt the thread[{}], try to force stop.", instanceId, threadName);
|
||||||
|
try {
|
||||||
|
thread.stop();
|
||||||
|
return true;
|
||||||
|
} catch (Throwable t) {
|
||||||
|
log.warn("[TaskTracker-{}] stop thread[{}] failed, msg: {}", instanceId, threadName, t.getMessage());
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user