diff --git a/common/src/main/java/org/dromara/dynamictp/common/constant/DingNotifyConst.java b/common/src/main/java/org/dromara/dynamictp/common/constant/DingNotifyConst.java index a0df744fe..f91250b31 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/constant/DingNotifyConst.java +++ b/common/src/main/java/org/dromara/dynamictp/common/constant/DingNotifyConst.java @@ -41,14 +41,28 @@ private DingNotifyConst() { } public static final String DING_NOTICE_TITLE = "动态线程池通知"; - public static final String DING_ALARM_TEMPLATE = + public static final String DING_ALARM_TEMPLATE_PREFIX = "【报警】 动态线程池运行告警 \n\n" + "服务名称:%s \n\n " + "实例信息:%s \n\n " + "环境:%s \n\n " + "线程池名称:%s \n\n " + "报警项:%s \n\n " + - "报警阈值 / 当前值:%s \n\n " + + "报警阈值 / 当前值:%s \n\n "; + + public static final String DING_ALARM_COMMON_TEMPLATE = + "%s \n\n "; + + public static final String DING_ALARM_TEMPLATE_SUFFIX = + "上次报警时间:%s \n\n" + + "报警时间:%s \n\n" + + "接收人:@%s \n\n" + + "trace 信息:%s \n\n" + + "报警间隔:%ss \n\n" + + "扩展信息:%s \n\n"; + + public static final String DING_ALARM_TEMPLATE = + DING_ALARM_TEMPLATE_PREFIX + "核心线程数:%d \n\n " + "最大线程数:%d \n\n " + "当前线程数:%d \n\n " + @@ -65,12 +79,7 @@ private DingNotifyConst() { } "总拒绝任务数量:%s \n\n " + "总执行超时任务数量:%s \n\n " + "总等待超时任务数量:%s \n\n " + - "上次报警时间:%s \n\n" + - "报警时间:%s \n\n" + - "接收人:@%s \n\n" + - "trace 信息:%s \n\n" + - "报警间隔:%ss \n\n" + - "扩展信息:%s \n\n"; + DING_ALARM_TEMPLATE_SUFFIX; public static final String DING_CHANGE_NOTICE_TEMPLATE = "【通知】 动态线程池参数变更 \n\n " + diff --git a/common/src/main/java/org/dromara/dynamictp/common/constant/DynamicTpConst.java b/common/src/main/java/org/dromara/dynamictp/common/constant/DynamicTpConst.java index 579d9af4b..052b554ff 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/constant/DynamicTpConst.java +++ b/common/src/main/java/org/dromara/dynamictp/common/constant/DynamicTpConst.java @@ -129,7 +129,15 @@ private DynamicTpConst() { } public static final String FALSE_STR = "false"; /** - * jre + * jre 21 */ public static final String THREAD_PER_TASK_EXECUTOR = "java.util.concurrent.ThreadPerTaskExecutor"; + + public static final String PINNED_EVENT = "jdk.VirtualThreadPinned"; + + public static final String MAX_PINNED_TIME = "maxPinnedTime"; + + public static final String TOTAL_PINNED_TIME = "totalPinnedTime"; + + public static final String PINNED_DURATION = "pinnedDuration"; } diff --git a/common/src/main/java/org/dromara/dynamictp/common/constant/LarkNotifyConst.java b/common/src/main/java/org/dromara/dynamictp/common/constant/LarkNotifyConst.java index 4e9642bf6..d08bda69e 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/constant/LarkNotifyConst.java +++ b/common/src/main/java/org/dromara/dynamictp/common/constant/LarkNotifyConst.java @@ -60,11 +60,20 @@ private LarkNotifyConst() { } public static final String SIGN_PARAM_PREFIX = "{\"timestamp\": \"%s\",\"sign\": \"%s\","; + public static final String LARK_ALARM_JSON_STR_PREFIX = + "{\"msg_type\":\"interactive\",\"card\":{\"config\":{\"wide_screen_mode\":true},\"header\":{\"template\":\"red\",\"title\":{\"tag\":\"plain_text\",\"content\":\"【报警】 动态线程池告警\"}},\"elements\":[{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**服务名称:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**实例信息:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**环境:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**线程池名称:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"alarmType **报警项:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"alarmValue **报警阈值 / 当前值:**\\n%s\"}}]},{\"tag\":\"hr\"},"; + + public static final String LARK_ALARM_JSON_COMMON_STR = + "{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"%s\"}}]},"; + + public static final String LARK_ALARM_JSON_STR_SUFFIX = + "{\"tag\":\"hr\"},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**上次报警时间:**\\n %s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**报警时间:**\\n %s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**接收人:**\\n %s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**trace 信息:**\\n %s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**报警间隔:**\\n %ss\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**扩展信息:**\\n %s\"}}]}]}}"; + /** * lark alarm json str */ public static final String LARK_ALARM_JSON_STR = - "{\"msg_type\":\"interactive\",\"card\":{\"config\":{\"wide_screen_mode\":true},\"header\":{\"template\":\"red\",\"title\":{\"tag\":\"plain_text\",\"content\":\"【报警】 动态线程池告警\"}},\"elements\":[{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**服务名称:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**实例信息:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**环境:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**线程池名称:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"alarmType **报警项:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"alarmValue **报警阈值 / 当前值:**\\n%s\"}}]},{\"tag\":\"hr\"},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"corePoolSize **核心线程数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"maximumPoolSize **最大线程数:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"poolSize **当前线程数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"activeCount **活跃线程数:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**历史最大线程数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**任务总数:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**执行完成任务数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**等待执行任务数:**\\n%s\"}}]},{\"tag\":\"hr\"},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueType **队列类型:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueCapacity **队列容量:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueSize **队列任务数量:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueRemaining **队列剩余容量:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"rejectType **拒绝策略:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"rejectCount **总拒绝任务数量:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"runTimeoutCount **总执行超时任务数量:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueTimeoutCount **总等待超时任务数量:**\\n%s\"}}]},{\"tag\":\"hr\"},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**上次报警时间:**\\n %s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**报警时间:**\\n %s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**接收人:**\\n %s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**trace 信息:**\\n %s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**报警间隔:**\\n %ss\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**扩展信息:**\\n %s\"}}]}]}}"; + LARK_ALARM_JSON_STR_PREFIX + "{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"corePoolSize **核心线程数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"maximumPoolSize **最大线程数:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"poolSize **当前线程数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"activeCount **活跃线程数:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**历史最大线程数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**任务总数:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**执行完成任务数:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"**等待执行任务数:**\\n%s\"}}]},{\"tag\":\"hr\"},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueType **队列类型:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueCapacity **队列容量:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueSize **队列任务数量:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueRemaining **队列剩余容量:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"rejectType **拒绝策略:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"rejectCount **总拒绝任务数量:**\\n%s\"}}]},{\"tag\":\"div\",\"fields\":[{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"runTimeoutCount **总执行超时任务数量:**\\n%s\"}},{\"is_short\":true,\"text\":{\"tag\":\"lark_md\",\"content\":\"queueTimeoutCount **总等待超时任务数量:**\\n%s\"}}]}," + LARK_ALARM_JSON_STR_SUFFIX; /** * lark notice json str diff --git a/common/src/main/java/org/dromara/dynamictp/common/constant/WechatNotifyConst.java b/common/src/main/java/org/dromara/dynamictp/common/constant/WechatNotifyConst.java index d5ca983a3..708e5afaa 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/constant/WechatNotifyConst.java +++ b/common/src/main/java/org/dromara/dynamictp/common/constant/WechatNotifyConst.java @@ -37,17 +37,31 @@ private WechatNotifyConst() { } public static final String COMMENT_COLOR = "comment"; - /** - * receivers only supports userid, view more, see more. - */ - public static final String WECHAT_ALARM_TEMPLATE = + public static final String WECHAT_ALARM_TEMPLATE_PREFIX = "【报警】 动态线程池告警 \n" + "> 服务名称:%s \n" + "> 实例信息:%s \n" + "> 环境:%s \n" + "> 线程池名称:%s \n" + "> 报警项:%s \n" + - "> 报警阈值 / 当前值:%s \n" + + "> 报警阈值 / 当前值:%s \n"; + + public static final String WECHAT_ALARM_COMMON_TEMPLATE = + "> %s \n"; + + public static final String WECHAT_ALARM_TEMPLATE_SUFFIX = + "> 上次报警时间:%s \n" + + "> 报警时间:%s \n" + + "> 接收人:%s \n" + + "> trace 信息:%s \n" + + "> 报警间隔:%ss \n" + + "> 扩展信息:%s \n"; + + /** + * receivers only supports userid, view more, see more. + */ + public static final String WECHAT_ALARM_TEMPLATE = + WECHAT_ALARM_TEMPLATE_PREFIX + "> 核心线程数:%s \n" + "> 最大线程数:%s \n" + "> 当前线程数:%s \n" + @@ -64,12 +78,7 @@ private WechatNotifyConst() { } "> 总拒绝任务数量:%s \n" + "> 总执行超时任务数量:%s \n" + "> 总等待超时任务数量:%s \n" + - "> 上次报警时间:%s \n" + - "> 报警时间:%s \n" + - "> 接收人:%s \n" + - "> trace 信息:%s \n" + - "> 报警间隔:%ss \n" + - "> 扩展信息:%s \n"; + WECHAT_ALARM_TEMPLATE_SUFFIX; public static final String WECHAT_CHANGE_NOTICE_TEMPLATE = "【通知】 动态线程池参数变更 \n" + diff --git a/common/src/main/java/org/dromara/dynamictp/common/em/NotifyItemEnum.java b/common/src/main/java/org/dromara/dynamictp/common/em/NotifyItemEnum.java index 10329bd15..a33aa03e5 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/em/NotifyItemEnum.java +++ b/common/src/main/java/org/dromara/dynamictp/common/em/NotifyItemEnum.java @@ -59,7 +59,12 @@ public enum NotifyItemEnum { /** * Task queue wait timeout alarm. */ - QUEUE_TIMEOUT("queue_timeout", ""); + QUEUE_TIMEOUT("queue_timeout", ""), + + /** + * Pin timeout alarm. + */ + PIN_TIMEOUT("pin_timeout", ""); private final String value; diff --git a/common/src/main/java/org/dromara/dynamictp/common/entity/ExecutorStats.java b/common/src/main/java/org/dromara/dynamictp/common/entity/ExecutorStats.java index ac86972e6..979e61bcd 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/entity/ExecutorStats.java +++ b/common/src/main/java/org/dromara/dynamictp/common/entity/ExecutorStats.java @@ -20,6 +20,9 @@ import lombok.Data; import lombok.EqualsAndHashCode; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; + /** * ExecutorStats related @@ -74,7 +77,12 @@ public class ExecutorStats extends Metrics { /** * 是否为虚拟线程执行器 */ - private boolean isVirtualExecutor; + private boolean isVirtualThreadExecutor; + + /** + * 拓展字段 + */ + private final Map extMap = new ConcurrentHashMap<>(2); /** * 空闲时间 (ms) diff --git a/common/src/main/java/org/dromara/dynamictp/common/entity/NotifyItem.java b/common/src/main/java/org/dromara/dynamictp/common/entity/NotifyItem.java index 0b1e50fc4..39b0dbf9f 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/entity/NotifyItem.java +++ b/common/src/main/java/org/dromara/dynamictp/common/entity/NotifyItem.java @@ -82,7 +82,7 @@ public static List mergeAllNotifyItems(List source) { val defaultItems = getAllNotifyItems().stream() .filter(t -> !StringUtil.containsIgnoreCase(t.getType(), configuredTypes)) .collect(Collectors.toList()); - List notifyItems = new ArrayList<>(6); + List notifyItems = new ArrayList<>(7); notifyItems.addAll(defaultItems); notifyItems.addAll(source); return notifyItems; @@ -102,11 +102,16 @@ public static List getAllNotifyItems() { queueTimeoutNotify.setType(NotifyItemEnum.QUEUE_TIMEOUT.getValue()); queueTimeoutNotify.setThreshold(10); - List notifyItems = new ArrayList<>(6); + NotifyItem pinTimeoutNotify = new NotifyItem(); + pinTimeoutNotify.setType(NotifyItemEnum.PIN_TIMEOUT.getValue()); + pinTimeoutNotify.setThreshold(10); + + List notifyItems = new ArrayList<>(7); notifyItems.addAll(getSimpleNotifyItems()); notifyItems.add(rejectNotify); notifyItems.add(runTimeoutNotify); notifyItems.add(queueTimeoutNotify); + notifyItems.add(pinTimeoutNotify); return notifyItems; } diff --git a/common/src/main/java/org/dromara/dynamictp/common/util/ExecutorUtil.java b/common/src/main/java/org/dromara/dynamictp/common/util/ExecutorUtil.java index 5005638b8..951de5668 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/util/ExecutorUtil.java +++ b/common/src/main/java/org/dromara/dynamictp/common/util/ExecutorUtil.java @@ -51,7 +51,7 @@ private static void tryPrintError(Runnable r, Throwable t) { if (r instanceof FutureTask) { try { FutureTask future = (FutureTask) r; - if (future.isDone()) { + if (future.isDone() && !future.isCancelled()) { future.get(); } } catch (InterruptedException e) { diff --git a/common/src/main/java/org/dromara/dynamictp/common/util/StringUtil.java b/common/src/main/java/org/dromara/dynamictp/common/util/StringUtil.java index 61743f647..c30419926 100644 --- a/common/src/main/java/org/dromara/dynamictp/common/util/StringUtil.java +++ b/common/src/main/java/org/dromara/dynamictp/common/util/StringUtil.java @@ -17,9 +17,12 @@ package org.dromara.dynamictp.common.util; +import jdk.jfr.consumer.RecordedFrame; +import jdk.jfr.consumer.RecordedStackTrace; import org.apache.commons.collections4.CollectionUtils; import java.util.Collection; +import java.util.stream.Collectors; /** * StringUtil related @@ -64,4 +67,22 @@ public static boolean containsIgnoreCase(CharSequence str, CharSequence testStr) } return str.toString().toLowerCase().contains(testStr.toString().toLowerCase()); } + + public static String formatJfrStackTrace(RecordedStackTrace stackTrace, int maxDepth) { + if (stackTrace == null) { + return "\t"; + } + String formatted = "\t" + stackTrace.getFrames().stream() + .limit(maxDepth) + .map(StringUtil::formatStackTraceFrame) + .collect(Collectors.joining("\n\t")); + if (maxDepth < stackTrace.getFrames().size()) { + return formatted + "\n\t(...)"; + } + return formatted; + } + + private static String formatStackTraceFrame(RecordedFrame frame) { + return frame.getMethod().getType().getName() + "#" + frame.getMethod().getName() + ": " + frame.getLineNumber(); + } } diff --git a/core/src/main/java/org/dromara/dynamictp/core/DtpRegistry.java b/core/src/main/java/org/dromara/dynamictp/core/DtpRegistry.java index 392e515ec..cba36ad46 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/DtpRegistry.java +++ b/core/src/main/java/org/dromara/dynamictp/core/DtpRegistry.java @@ -44,6 +44,7 @@ import org.dromara.dynamictp.core.reject.RejectHandlerGetter; import org.dromara.dynamictp.core.support.adapter.ExecutorAdapter; import org.dromara.dynamictp.core.support.ExecutorWrapper; +import org.dromara.dynamictp.core.support.proxy.VirtualThreadExecutorProxy; import org.dromara.dynamictp.core.support.task.wrapper.TaskWrapper; import org.dromara.dynamictp.core.support.task.wrapper.TaskWrappers; @@ -220,6 +221,10 @@ private static void refresh(ExecutorWrapper executorWrapper, DtpExecutorProps pr private static void doRefresh(ExecutorWrapper executorWrapper, DtpExecutorProps props) { ExecutorAdapter executor = executorWrapper.getExecutor(); + if (executorWrapper.isVirtualThreadExecutor()) { + doRefreshCommon(executorWrapper, props); + return; + } doRefreshPoolSize(executor, props); if (!Objects.equals(executor.getKeepAliveTime(props.getUnit()), props.getKeepAliveTime())) { executor.setKeepAliveTime(props.getKeepAliveTime(), props.getUnit()); @@ -300,9 +305,13 @@ private static void doRefreshDtp(ExecutorWrapper executorWrapper, DtpExecutorPro } private static void updateWrapper(ExecutorWrapper executorWrapper, DtpExecutorProps props) { - if (executorWrapper.isDtpExecutor()) { + if (executorWrapper.isDtpExecutor() || executorWrapper.isVirtualThreadExecutor()) { executorWrapper.setThreadPoolAliasName(props.getThreadPoolAliasName()); - executorWrapper.setNotifyItems(((DtpExecutor) executorWrapper.getExecutor()).getNotifyItems()); + if (executorWrapper.isDtpExecutor()) { + executorWrapper.setNotifyItems(((DtpExecutor) executorWrapper.getExecutor()).getNotifyItems()); + } else { + executorWrapper.setNotifyItems(((VirtualThreadExecutorProxy) executorWrapper.getExecutor().getOriginal()).getNotifyItems()); + } executorWrapper.setPlatformIds(props.getPlatformIds()); executorWrapper.setNotifyEnabled(props.isNotifyEnabled()); } @@ -339,7 +348,6 @@ private static void doRefreshPoolSize(ExecutorAdapter executor, DtpExecutorPr } private static void updateQueueProps(ExecutorAdapter executor, DtpExecutorProps props) { - val blockingQueue = executor.getQueue(); if (blockingQueue instanceof MemorySafeLinkedBlockingQueue) { ((MemorySafeLinkedBlockingQueue) blockingQueue).setMaxFreeMemory(props.getMaxFreeMemory() * M_1); diff --git a/core/src/main/java/org/dromara/dynamictp/core/aware/TaskRejectAware.java b/core/src/main/java/org/dromara/dynamictp/core/aware/TaskRejectAware.java index ffb0af7b0..e925f5916 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/aware/TaskRejectAware.java +++ b/core/src/main/java/org/dromara/dynamictp/core/aware/TaskRejectAware.java @@ -21,7 +21,7 @@ import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.core.notifier.manager.AlarmManager; import org.dromara.dynamictp.core.support.adapter.ExecutorAdapter; -import org.dromara.dynamictp.core.support.ThreadPoolStatProvider; +import org.dromara.dynamictp.core.support.ExecutorStatProvider; import org.slf4j.MDC; import java.util.Objects; @@ -51,7 +51,7 @@ public String getName() { @Override public void beforeReject(Runnable runnable, Executor executor) { - ThreadPoolStatProvider statProvider = statProviders.get(executor); + ExecutorStatProvider statProvider = statProviders.get(executor); if (Objects.isNull(statProvider)) { return; } diff --git a/core/src/main/java/org/dromara/dynamictp/core/aware/TaskStatAware.java b/core/src/main/java/org/dromara/dynamictp/core/aware/TaskStatAware.java index 3c726492d..e0ec2c820 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/aware/TaskStatAware.java +++ b/core/src/main/java/org/dromara/dynamictp/core/aware/TaskStatAware.java @@ -19,7 +19,7 @@ import org.dromara.dynamictp.common.entity.TpExecutorProps; import org.dromara.dynamictp.core.support.ExecutorWrapper; -import org.dromara.dynamictp.core.support.ThreadPoolStatProvider; +import org.dromara.dynamictp.core.support.ExecutorStatProvider; import java.util.Map; import java.util.Objects; @@ -34,11 +34,11 @@ */ public abstract class TaskStatAware implements ExecutorAware { - protected final Map statProviders = new ConcurrentHashMap<>(); + protected final Map statProviders = new ConcurrentHashMap<>(); @Override public void register(ExecutorWrapper wrapper) { - ThreadPoolStatProvider statProvider = wrapper.getThreadPoolStatProvider(); + ExecutorStatProvider statProvider = wrapper.getExecutorStatProvider(); statProviders.put(wrapper.getExecutor(), statProvider); statProviders.put(wrapper.getExecutor().getOriginal(), statProvider); } @@ -48,7 +48,7 @@ public void refresh(ExecutorWrapper wrapper, TpExecutorProps props) { if (Objects.isNull(statProviders.get(wrapper.getExecutor()))) { register(wrapper); } - ThreadPoolStatProvider statProvider = wrapper.getThreadPoolStatProvider(); + ExecutorStatProvider statProvider = wrapper.getExecutorStatProvider(); refresh(props, statProvider); } @@ -58,5 +58,5 @@ public void remove(ExecutorWrapper wrapper) { statProviders.remove(wrapper.getExecutor().getOriginal()); } - protected void refresh(TpExecutorProps props, ThreadPoolStatProvider statProvider) { } + protected void refresh(TpExecutorProps props, ExecutorStatProvider statProvider) { } } diff --git a/core/src/main/java/org/dromara/dynamictp/core/aware/TaskTimeoutAware.java b/core/src/main/java/org/dromara/dynamictp/core/aware/TaskTimeoutAware.java index bce9260aa..b8b89384d 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/aware/TaskTimeoutAware.java +++ b/core/src/main/java/org/dromara/dynamictp/core/aware/TaskTimeoutAware.java @@ -19,7 +19,7 @@ import lombok.extern.slf4j.Slf4j; import org.dromara.dynamictp.common.entity.TpExecutorProps; -import org.dromara.dynamictp.core.support.ThreadPoolStatProvider; +import org.dromara.dynamictp.core.support.ExecutorStatProvider; import java.util.Objects; import java.util.Optional; @@ -48,7 +48,7 @@ public String getName() { } @Override - protected void refresh(TpExecutorProps props, ThreadPoolStatProvider statProvider) { + protected void refresh(TpExecutorProps props, ExecutorStatProvider statProvider) { super.refresh(props, statProvider); if (Objects.nonNull(props)) { statProvider.setRunTimeout(props.getRunTimeout()); diff --git a/core/src/main/java/org/dromara/dynamictp/core/converter/ExecutorConverter.java b/core/src/main/java/org/dromara/dynamictp/core/converter/ExecutorConverter.java index b5da89dab..474f28b18 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/converter/ExecutorConverter.java +++ b/core/src/main/java/org/dromara/dynamictp/core/converter/ExecutorConverter.java @@ -24,8 +24,9 @@ import org.dromara.dynamictp.core.monitor.PerformanceProvider; import org.dromara.dynamictp.core.support.adapter.ExecutorAdapter; import org.dromara.dynamictp.core.support.ExecutorWrapper; -import org.dromara.dynamictp.core.support.ThreadPoolStatProvider; +import org.dromara.dynamictp.core.support.ExecutorStatProvider; +import java.util.Map; import java.util.concurrent.TimeUnit; /** @@ -58,7 +59,7 @@ public static ExecutorStats toMetrics(ExecutorWrapper wrapper) { if (executor == null) { return null; } - ThreadPoolStatProvider provider = wrapper.getThreadPoolStatProvider(); + ExecutorStatProvider provider = wrapper.getExecutorStatProvider(); PerformanceProvider performanceProvider = provider.getPerformanceProvider(); val performanceSnapshot = performanceProvider.getSnapshotAndReset(); ExecutorStats executorStats = convertCommon(executor); @@ -68,7 +69,8 @@ public static ExecutorStats toMetrics(ExecutorWrapper wrapper) { executorStats.setQueueTimeoutCount(provider.getQueueTimeoutCount()); executorStats.setRejectCount(provider.getRejectedTaskCount()); - executorStats.setVirtualExecutor(wrapper.isVirtualThreadExecutor()); + executorStats.setVirtualThreadExecutor(wrapper.isVirtualThreadExecutor()); + toVirtualThreadMetrics(executorStats); executorStats.setDynamic(executor instanceof DtpExecutor); executorStats.setTps(performanceSnapshot.getTps()); @@ -84,6 +86,15 @@ public static ExecutorStats toMetrics(ExecutorWrapper wrapper) { return executorStats; } + private static void toVirtualThreadMetrics(ExecutorStats executorStats) { + if (!executorStats.isVirtualThreadExecutor()) { + return; + } + Map vteStats = PerformanceProvider.getVteStat(executorStats.getExecutorName()); + executorStats.getExtMap().put("maxPinnedTime", vteStats.getOrDefault("maxPinnedTime", 0d)); + executorStats.getExtMap().put("totalPinnedTime", vteStats.getOrDefault("totalPinnedTime", 0d)); + } + private static ExecutorStats convertCommon(ExecutorAdapter executor) { ExecutorStats executorStats = new ExecutorStats(); executorStats.setCorePoolSize(executor.getCorePoolSize()); diff --git a/core/src/main/java/org/dromara/dynamictp/core/handler/NotifierHandler.java b/core/src/main/java/org/dromara/dynamictp/core/handler/NotifierHandler.java index 0a92d8254..110a68cdd 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/handler/NotifierHandler.java +++ b/core/src/main/java/org/dromara/dynamictp/core/handler/NotifierHandler.java @@ -29,9 +29,11 @@ import org.dromara.dynamictp.common.notifier.DingNotifier; import org.dromara.dynamictp.common.notifier.LarkNotifier; import org.dromara.dynamictp.common.notifier.WechatNotifier; +import org.dromara.dynamictp.core.notifier.context.BaseNotifyCtx; import org.dromara.dynamictp.core.notifier.context.DtpNotifyCtxHolder; import org.dromara.dynamictp.core.notifier.manager.NotifyHelper; +import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -72,12 +74,22 @@ public void sendNotice(TpMainFields oldFields, List diffs) { } public void sendAlarm(NotifyItemEnum notifyItemEnum) { - NotifyItem notifyItem = DtpNotifyCtxHolder.get().getNotifyItem(); + BaseNotifyCtx notifyCtx = DtpNotifyCtxHolder.get(); + if (notifyCtx.isToLog()) { + log.warn("DynamicTp alarm, executor [" + notifyCtx.getExecutorWrapper().getThreadPoolName() + "]: \n" + Arrays.toString(notifyCtx.getContent())); + } + NotifyItem notifyItem = notifyCtx.getNotifyItem(); for (String platformId : notifyItem.getPlatformIds()) { NotifyHelper.getPlatform(platformId).ifPresent(p -> { DtpNotifier notifier = NOTIFIERS.get(p.getPlatform().toLowerCase()); if (notifier != null) { - notifier.sendAlarmMsg(p, notifyItemEnum); + if (notifyCtx.isCommonNotify()) { + notifier.sendCommonAlarmMsg(p, notifyItemEnum, notifyCtx.getContent()); + } else { + if (!notifyCtx.getExecutorWrapper().isVirtualThreadExecutor()) { + notifier.sendAlarmMsg(p, notifyItemEnum); + } + } } }); } diff --git a/core/src/main/java/org/dromara/dynamictp/core/monitor/DtpMonitor.java b/core/src/main/java/org/dromara/dynamictp/core/monitor/DtpMonitor.java index b4ea4f55d..9a9aadfd5 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/monitor/DtpMonitor.java +++ b/core/src/main/java/org/dromara/dynamictp/core/monitor/DtpMonitor.java @@ -102,9 +102,9 @@ private void collectMetrics(Set executorNames) { } - private void doCollect(ExecutorStats threadPoolStats) { + private void doCollect(ExecutorStats executorStats) { try { - CollectorHandler.getInstance().collect(threadPoolStats, dtpProperties.getCollectorTypes()); + CollectorHandler.getInstance().collect(executorStats, dtpProperties.getCollectorTypes()); } catch (Exception e) { log.error("DynamicTp monitor, metrics collect error.", e); } diff --git a/core/src/main/java/org/dromara/dynamictp/core/monitor/PerformanceProvider.java b/core/src/main/java/org/dromara/dynamictp/core/monitor/PerformanceProvider.java index 1fcc06e0f..3e89790ab 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/monitor/PerformanceProvider.java +++ b/core/src/main/java/org/dromara/dynamictp/core/monitor/PerformanceProvider.java @@ -17,21 +17,42 @@ package org.dromara.dynamictp.core.monitor; +import com.google.common.collect.ImmutableList; +import io.micrometer.core.instrument.Timer; +import io.micrometer.core.instrument.simple.SimpleMeterRegistry; +import jdk.jfr.consumer.RecordedEvent; +import jdk.jfr.consumer.RecordingStream; import lombok.Getter; import lombok.val; +import org.dromara.dynamictp.common.em.NotifyItemEnum; +import org.dromara.dynamictp.core.DtpRegistry; import org.dromara.dynamictp.core.metric.MMAPCounter; +import org.dromara.dynamictp.core.notifier.manager.AlarmManager; +import org.dromara.dynamictp.core.support.ExecutorWrapper; +import org.dromara.dynamictp.core.support.proxy.VirtualThreadExecutorProxy; +import java.io.Closeable; import java.math.BigDecimal; import java.math.RoundingMode; +import java.time.Duration; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicLong; +import static org.dromara.dynamictp.common.constant.DynamicTpConst.MAX_PINNED_TIME; +import static org.dromara.dynamictp.common.constant.DynamicTpConst.PINNED_EVENT; +import static org.dromara.dynamictp.common.constant.DynamicTpConst.TOTAL_PINNED_TIME; +import static org.dromara.dynamictp.common.util.StringUtil.formatJfrStackTrace; + + /** * PerformanceProvider related * * @author kyao * @since 1.1.5 */ -public class PerformanceProvider { +public class PerformanceProvider implements Closeable { /** * last refresh timestamp @@ -40,6 +61,13 @@ public class PerformanceProvider { private final MMAPCounter mmapCounter = new MMAPCounter(); + private static final Map> VTE_STATS_CACHE = new ConcurrentHashMap<>(); + + private static final int DEFAULT_STACK_TRACE_MAX_DEPTH = 15; + + private static final Timer TIMER = new SimpleMeterRegistry().timer(PINNED_EVENT); + private static final RecordingStream RECORDING_STREAM = createRecordingStream(); + public void completeTask(long rt) { mmapCounter.add(rt); } @@ -57,6 +85,61 @@ private void reset(long currentMillis) { lastRefreshMillis.compareAndSet(lastRefreshMillis.get(), currentMillis); } + public static RecordingStream createRecordingStream() { + RecordingStream recordingStream = new RecordingStream(); + recordingStream.enable(PINNED_EVENT).withStackTrace(); + recordingStream.setMaxAge(Duration.ofSeconds(5)); + recordingStream.startAsync(); + recordingStream.onEvent(PINNED_EVENT, PerformanceProvider::handlePinnedEvent); + return recordingStream; + } + + @Override + public void close() { + RECORDING_STREAM.close(); + } + + /** + * When an event is pinned, the data is saved to the cache + */ + static void handlePinnedEvent(RecordedEvent event) { + String executorName = event.getThread() != null ? event.getThread().getJavaName() : ""; + if (executorName.isEmpty()) { + return; + } + Duration duration = event.getDuration(); + String stackTrace = formatJfrStackTrace(event.getStackTrace(), DEFAULT_STACK_TRACE_MAX_DEPTH); + TIMER.record(duration); + + ConcurrentHashMap vtExecutorStat = new ConcurrentHashMap<>(3); + double maxPinnedTime = TIMER.max(TimeUnit.MILLISECONDS); + double totalPinnedTime = TIMER.totalTime(TimeUnit.MILLISECONDS); + long durationPinnedTime = duration.toMillis(); + vtExecutorStat.put(MAX_PINNED_TIME, maxPinnedTime); + vtExecutorStat.put(TOTAL_PINNED_TIME, totalPinnedTime); + + String[] pinContent = populatePinContent(maxPinnedTime, totalPinnedTime, durationPinnedTime, stackTrace); + ExecutorWrapper executorWrapper = DtpRegistry.getExecutorWrapper(executorName); + ((VirtualThreadExecutorProxy) executorWrapper.getExecutor().getOriginal()).setCurPinDuration(duration.toSeconds()); + AlarmManager.tryCommonAlarmAsync(executorWrapper, ImmutableList.of(NotifyItemEnum.PIN_TIMEOUT), true, pinContent); + + VTE_STATS_CACHE.put(executorName, vtExecutorStat); + } + + private static String[] populatePinContent(double maxPinnedTime, double totalPinnedTime, long durationPinnedTime, String stackTrace) { + return new String[] { + "maxPinnedTime: " + maxPinnedTime + "ms", + "totalPinnedTime: " + totalPinnedTime + "ms", + "durationPinnedTime: " + durationPinnedTime + "ms", + "stackTrace: \n" + stackTrace + }; + } + + public static Map getVteStat(String executorName) { + VTE_STATS_CACHE.putIfAbsent(executorName, new ConcurrentHashMap<>(3)); + return VTE_STATS_CACHE.get(executorName); + } + @Getter public static class PerformanceSnapshot { diff --git a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/MicroMeterCollector.java b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/MicroMeterCollector.java index bd40efe99..923a3b03c 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/MicroMeterCollector.java +++ b/core/src/main/java/org/dromara/dynamictp/core/monitor/collector/MicroMeterCollector.java @@ -52,7 +52,7 @@ public class MicroMeterCollector extends AbstractCollector { public static final String APP_NAME_TAG = "app.name"; - private static final Map GAUGE_CACHE = new ConcurrentHashMap<>(); + public static final Map GAUGE_CACHE = new ConcurrentHashMap<>(); @Override public void collect(ExecutorStats executorStats) { diff --git a/core/src/main/java/org/dromara/dynamictp/core/notifier/AbstractDtpNotifier.java b/core/src/main/java/org/dromara/dynamictp/core/notifier/AbstractDtpNotifier.java index 9133673fa..1ff80b153 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/notifier/AbstractDtpNotifier.java +++ b/core/src/main/java/org/dromara/dynamictp/core/notifier/AbstractDtpNotifier.java @@ -40,6 +40,7 @@ import org.slf4j.MDC; import java.lang.reflect.Field; +import java.util.Arrays; import java.util.List; import java.util.Objects; import java.util.Optional; @@ -88,12 +89,22 @@ public void sendAlarmMsg(NotifyPlatform notifyPlatform, NotifyItemEnum notifyIte notifier.send(newTargetPlatform(notifyPlatform), content); } + @Override + public void sendCommonAlarmMsg(NotifyPlatform notifyPlatform, NotifyItemEnum notifyItemEnum, String... content) { + String formattedContent = buildCommonAlarmContent(notifyPlatform, notifyItemEnum, content); + if (StringUtils.isBlank(formattedContent) || StringUtils.isEmpty(Arrays.toString(content))) { + log.debug("Alarm content is empty, ignore send alarm message."); + return; + } + notifier.send(newTargetPlatform(notifyPlatform), formattedContent); + } + protected String buildAlarmContent(NotifyPlatform platform, NotifyItemEnum notifyItemEnum) { AlarmCtx context = (AlarmCtx) DtpNotifyCtxHolder.get(); ExecutorWrapper executorWrapper = context.getExecutorWrapper(); val executor = executorWrapper.getExecutor(); NotifyItem notifyItem = context.getNotifyItem(); - val statProvider = executorWrapper.getThreadPoolStatProvider(); + val statProvider = executorWrapper.getExecutorStatProvider(); val alarmValue = notifyItem.getThreshold() + notifyItemEnum.getUnit() + " / " + AlarmCounter.calcCurrentValue(executorWrapper, notifyItemEnum) + notifyItemEnum.getUnit(); String content = String.format( @@ -130,6 +141,39 @@ protected String buildAlarmContent(NotifyPlatform platform, NotifyItemEnum notif return highlightAlarmContent(content, notifyItemEnum); } + private String buildCommonAlarmContent(NotifyPlatform notifyPlatform, NotifyItemEnum notifyItemEnum, String... content) { + AlarmCtx context = (AlarmCtx) DtpNotifyCtxHolder.get(); + ExecutorWrapper executorWrapper = context.getExecutorWrapper(); + NotifyItem notifyItem = context.getNotifyItem(); + val alarmValue = notifyItem.getThreshold() + notifyItemEnum.getUnit() + " / " + + AlarmCounter.calcCurrentValue(executorWrapper, notifyItemEnum) + notifyItemEnum.getUnit(); + String[] template = getCommonAlarmTemplate(content.length); + String formatContentPrefix = String.format( + template[0], + CommonUtil.getInstance().getServiceName(), + CommonUtil.getInstance().getIp() + ":" + CommonUtil.getInstance().getPort(), + CommonUtil.getInstance().getEnv(), + populatePoolName(executorWrapper), + populateAlarmItem(notifyItemEnum, executorWrapper), + alarmValue + ); + String formatCommonContent = String.format( + template[1], + content + ); + String formatContentSuffix = String.format( + template[2], + Optional.ofNullable(context.getAlarmInfo()).map(AlarmInfo::getLastAlarmTime).orElse(UNKNOWN), + DateUtil.now(), + getReceives(notifyItem, notifyPlatform), + getTraceInfo(), + notifyItem.getInterval(), + getExtInfo() + ); + String formatContent = formatContentPrefix + formatCommonContent + formatContentSuffix; + return highlightAlarmContent(formatContent, notifyItemEnum); + } + protected String buildNoticeContent(NotifyPlatform platform, TpMainFields oldFields, List diffs) { BaseNotifyCtx context = DtpNotifyCtxHolder.get(); ExecutorWrapper executorWrapper = context.getExecutorWrapper(); @@ -202,9 +246,9 @@ protected String populatePoolName(ExecutorWrapper executorWrapper) { protected String populateAlarmItem(NotifyItemEnum notifyType, ExecutorWrapper executorWrapper) { String suffix = StringUtils.EMPTY; if (notifyType == NotifyItemEnum.RUN_TIMEOUT) { - suffix = " (" + executorWrapper.getThreadPoolStatProvider().getRunTimeout() + "ms)"; + suffix = " (" + executorWrapper.getExecutorStatProvider().getRunTimeout() + "ms)"; } else if (notifyType == NotifyItemEnum.QUEUE_TIMEOUT) { - suffix = " (" + executorWrapper.getThreadPoolStatProvider().getQueueTimeout() + "ms)"; + suffix = " (" + executorWrapper.getExecutorStatProvider().getQueueTimeout() + "ms)"; } return notifyType.getValue() + suffix; } @@ -254,6 +298,14 @@ private String highlightAlarmContent(String content, NotifyItemEnum notifyItemEn */ protected abstract String getAlarmTemplate(); + /** + * Implement by subclass, get common alarm template. + * + * @param num number of args + * @return alarm template + */ + protected abstract String[] getCommonAlarmTemplate(int num); + /** * Implement by subclass, get content color config. * diff --git a/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpDingNotifier.java b/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpDingNotifier.java index 46a321b95..c6881fe22 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpDingNotifier.java +++ b/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpDingNotifier.java @@ -52,6 +52,11 @@ protected String getAlarmTemplate() { return DingNotifyConst.DING_ALARM_TEMPLATE; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{DingNotifyConst.DING_ALARM_TEMPLATE_PREFIX, DingNotifyConst.DING_ALARM_COMMON_TEMPLATE.repeat(Math.max(0, num)), DingNotifyConst.DING_ALARM_TEMPLATE_SUFFIX}; + } + @Override protected Pair getColors() { return new ImmutablePair<>(DingNotifyConst.WARNING_COLOR, DingNotifyConst.CONTENT_COLOR); diff --git a/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpLarkNotifier.java b/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpLarkNotifier.java index 2bac20543..ed2a25b78 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpLarkNotifier.java +++ b/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpLarkNotifier.java @@ -61,6 +61,11 @@ protected String getAlarmTemplate() { return LarkNotifyConst.LARK_ALARM_JSON_STR; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{LarkNotifyConst.LARK_ALARM_JSON_STR_PREFIX, LarkNotifyConst.LARK_ALARM_JSON_COMMON_STR.repeat(Math.max(0, num)), LarkNotifyConst.LARK_ALARM_JSON_STR_SUFFIX}; + } + @Override protected Pair getColors() { return new ImmutablePair<>(LarkNotifyConst.WARNING_COLOR, LarkNotifyConst.COMMENT_COLOR); diff --git a/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpNotifier.java b/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpNotifier.java index f1e804e9e..f79b64254 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpNotifier.java +++ b/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpNotifier.java @@ -54,4 +54,13 @@ public interface DtpNotifier { * @param notifyItemEnum notify item enum */ void sendAlarmMsg(NotifyPlatform notifyPlatform, NotifyItemEnum notifyItemEnum); + + /** + * Send common alarm message. + * + * @param notifyPlatform notify platform + * @param notifyItemEnum notify item enum + * @param content common content + */ + void sendCommonAlarmMsg(NotifyPlatform notifyPlatform, NotifyItemEnum notifyItemEnum, String... content); } diff --git a/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpWechatNotifier.java b/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpWechatNotifier.java index 1faa1ceaa..c738ce3a0 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpWechatNotifier.java +++ b/core/src/main/java/org/dromara/dynamictp/core/notifier/DtpWechatNotifier.java @@ -56,6 +56,11 @@ protected String getAlarmTemplate() { return WechatNotifyConst.WECHAT_ALARM_TEMPLATE; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{WechatNotifyConst.WECHAT_ALARM_TEMPLATE_PREFIX, WechatNotifyConst.WECHAT_ALARM_COMMON_TEMPLATE.repeat(Math.max(0, num)), WechatNotifyConst.WECHAT_ALARM_TEMPLATE_SUFFIX}; + } + @Override protected Pair getColors() { return new ImmutablePair<>(WechatNotifyConst.WARNING_COLOR, WechatNotifyConst.COMMENT_COLOR); diff --git a/core/src/main/java/org/dromara/dynamictp/core/notifier/alarm/AlarmCounter.java b/core/src/main/java/org/dromara/dynamictp/core/notifier/alarm/AlarmCounter.java index b236431f2..3a46e07c0 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/notifier/alarm/AlarmCounter.java +++ b/core/src/main/java/org/dromara/dynamictp/core/notifier/alarm/AlarmCounter.java @@ -77,6 +77,9 @@ public static void incAlarmCounter(String threadPoolName, String notifyItemType) public static int calcCurrentValue(ExecutorWrapper wrapper, NotifyItemEnum itemEnum) { val executor = wrapper.getExecutor(); + if (wrapper.isVirtualThreadExecutor()) { + return Integer.MAX_VALUE; + } switch (itemEnum) { case CAPACITY: return (int) (NumberUtil.div(executor.getQueueSize(), executor.getQueueCapacity(), 2) * 100); diff --git a/core/src/main/java/org/dromara/dynamictp/core/notifier/context/AlarmCtx.java b/core/src/main/java/org/dromara/dynamictp/core/notifier/context/AlarmCtx.java index 5e43ef88e..2d067a184 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/notifier/context/AlarmCtx.java +++ b/core/src/main/java/org/dromara/dynamictp/core/notifier/context/AlarmCtx.java @@ -36,6 +36,13 @@ public class AlarmCtx extends BaseNotifyCtx { private AlarmInfo alarmInfo; public AlarmCtx(ExecutorWrapper wrapper, NotifyItem notifyItem) { - super(wrapper, notifyItem); + this(wrapper, notifyItem, false, ""); + } + + public AlarmCtx(ExecutorWrapper wrapper, NotifyItem notifyItem, boolean isCommonNotify, String... content) { + this(wrapper, notifyItem, isCommonNotify, false, content); + } + public AlarmCtx(ExecutorWrapper wrapper, NotifyItem notifyItem, boolean isCommonNotify, boolean isToLog, String... content) { + super(wrapper, notifyItem, isCommonNotify, isToLog, content); } } diff --git a/core/src/main/java/org/dromara/dynamictp/core/notifier/context/BaseNotifyCtx.java b/core/src/main/java/org/dromara/dynamictp/core/notifier/context/BaseNotifyCtx.java index 432d42c1d..ef22a37bc 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/notifier/context/BaseNotifyCtx.java +++ b/core/src/main/java/org/dromara/dynamictp/core/notifier/context/BaseNotifyCtx.java @@ -35,11 +35,24 @@ public class BaseNotifyCtx { private NotifyItem notifyItem; + private boolean isCommonNotify; + + private boolean isToLog; + + private String[] content; + public BaseNotifyCtx() { } public BaseNotifyCtx(ExecutorWrapper wrapper, NotifyItem notifyItem) { + this(wrapper, notifyItem, false, false, ""); + } + + public BaseNotifyCtx(ExecutorWrapper wrapper, NotifyItem notifyItem, boolean isCommonNotify, boolean isToLog, String... content) { this.executorWrapper = wrapper.capture(); this.notifyItem = notifyItem; + this.isCommonNotify = isCommonNotify; + this.isToLog = isToLog; + this.content = content; } public NotifyItemEnum getNotifyItemEnum() { diff --git a/core/src/main/java/org/dromara/dynamictp/core/notifier/manager/AlarmManager.java b/core/src/main/java/org/dromara/dynamictp/core/notifier/manager/AlarmManager.java index 378986196..bb02e787d 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/notifier/manager/AlarmManager.java +++ b/core/src/main/java/org/dromara/dynamictp/core/notifier/manager/AlarmManager.java @@ -32,6 +32,8 @@ import org.dromara.dynamictp.core.notifier.context.BaseNotifyCtx; import org.dromara.dynamictp.core.support.ExecutorWrapper; import org.dromara.dynamictp.core.support.ThreadPoolBuilder; +import org.dromara.dynamictp.core.support.adapter.VirtualThreadExecutorAdapter; +import org.dromara.dynamictp.core.support.proxy.VirtualThreadExecutorProxy; import org.dromara.dynamictp.core.support.task.runnable.DtpRunnable; import org.dromara.dynamictp.core.support.task.wrapper.TaskWrappers; import org.slf4j.MDC; @@ -91,10 +93,18 @@ public static void tryAlarmAsync(ExecutorWrapper executorWrapper, List notifyTypes.forEach(x -> doTryAlarm(executorWrapper, x))); } + public static void tryCommonAlarmAsync(ExecutorWrapper executorWrapper, List notifyTypes, boolean isToLog, String... content) { + ALARM_EXECUTOR.execute(() -> notifyTypes.forEach(x -> doTryAlarm(executorWrapper, x, true, isToLog, content))); + } + public static void doTryAlarm(ExecutorWrapper executorWrapper, NotifyItemEnum notifyType) { + doTryAlarm(executorWrapper, notifyType, false, false, ""); + } + + public static void doTryAlarm(ExecutorWrapper executorWrapper, NotifyItemEnum notifyType, boolean isCommonNotify, boolean isToLog, String... content) { AlarmCounter.incAlarmCounter(executorWrapper.getThreadPoolName(), notifyType.getValue()); NotifyHelper.getNotifyItem(executorWrapper, notifyType).ifPresent(notifyItem -> { - val alarmCtx = new AlarmCtx(executorWrapper, notifyItem); + val alarmCtx = new AlarmCtx(executorWrapper, notifyItem, isCommonNotify, isToLog, content); ALARM_INVOKER_CHAIN.proceed(alarmCtx); }); } @@ -106,6 +116,8 @@ public static boolean checkThreshold(ExecutorWrapper executor, NotifyItemEnum no return checkCapacity(executor, notifyItem); case LIVENESS: return checkLiveness(executor, notifyItem); + case PIN_TIMEOUT: + return checkPinTimeout(executor, notifyItem); case REJECT: case RUN_TIMEOUT: case QUEUE_TIMEOUT: @@ -116,11 +128,15 @@ public static boolean checkThreshold(ExecutorWrapper executor, NotifyItemEnum no } } + public static void destroy() { ALARM_EXECUTOR.shutdownNow(); } private static boolean checkLiveness(ExecutorWrapper executorWrapper, NotifyItem notifyItem) { + if (executorWrapper.isVirtualThreadExecutor()) { + return true; + } val executor = executorWrapper.getExecutor(); int maximumPoolSize = executor.getMaximumPoolSize(); double div = NumberUtil.div(executor.getActiveCount(), maximumPoolSize, 2) * 100; @@ -128,7 +144,9 @@ private static boolean checkLiveness(ExecutorWrapper executorWrapper, NotifyItem } private static boolean checkCapacity(ExecutorWrapper executorWrapper, NotifyItem notifyItem) { - + if (executorWrapper.isVirtualThreadExecutor()) { + return true; + } val executor = executorWrapper.getExecutor(); if (executor.getQueueSize() <= 0) { return false; @@ -137,6 +155,11 @@ private static boolean checkCapacity(ExecutorWrapper executorWrapper, NotifyItem return div >= notifyItem.getThreshold(); } + private static boolean checkPinTimeout(ExecutorWrapper executorWrapper, NotifyItem notifyItem) { + return ((VirtualThreadExecutorProxy) ((VirtualThreadExecutorAdapter) executorWrapper.getExecutor().getOriginal()) + .getOriginal()).getCurPinDuration() >= notifyItem.getThreshold(); + } + private static boolean checkWithAlarmInfo(ExecutorWrapper executorWrapper, NotifyItem notifyItem) { AlarmInfo alarmInfo = AlarmCounter.getAlarmInfo(executorWrapper.getThreadPoolName(), notifyItem.getType()); return alarmInfo.getCount() >= notifyItem.getThreshold(); diff --git a/core/src/main/java/org/dromara/dynamictp/core/notifier/manager/NotifyHelper.java b/core/src/main/java/org/dromara/dynamictp/core/notifier/manager/NotifyHelper.java index cb923291f..2483d7e34 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/notifier/manager/NotifyHelper.java +++ b/core/src/main/java/org/dromara/dynamictp/core/notifier/manager/NotifyHelper.java @@ -34,6 +34,7 @@ import org.dromara.dynamictp.common.manager.ContextManagerHelper; import org.dromara.dynamictp.core.support.ExecutorWrapper; +import org.dromara.dynamictp.core.support.proxy.VirtualThreadExecutorProxy; import java.util.Collection; import java.util.Collections; @@ -44,11 +45,7 @@ import java.util.Set; import java.util.stream.Collectors; -import static org.dromara.dynamictp.common.em.NotifyItemEnum.CAPACITY; -import static org.dromara.dynamictp.common.em.NotifyItemEnum.LIVENESS; -import static org.dromara.dynamictp.common.em.NotifyItemEnum.QUEUE_TIMEOUT; -import static org.dromara.dynamictp.common.em.NotifyItemEnum.REJECT; -import static org.dromara.dynamictp.common.em.NotifyItemEnum.RUN_TIMEOUT; +import static org.dromara.dynamictp.common.em.NotifyItemEnum.*; import static org.dromara.dynamictp.common.entity.NotifyItem.mergeAllNotifyItems; /** @@ -74,6 +71,8 @@ public class NotifyHelper { private static final Set QUEUE_TIMEOUT_ALARM_KEYS = Sets.newHashSet("queueTimeoutCount"); + private static final Set PIN_TIMEOUT_ALARM_KEYS = Sets.newHashSet("pinTimeoutCount"); + private static final Set ALL_ALARM_KEYS; private static final Map> ALARM_KEYS = Maps.newHashMap(); @@ -84,6 +83,7 @@ public class NotifyHelper { ALARM_KEYS.put(REJECT.name(), REJECT_ALARM_KEYS); ALARM_KEYS.put(RUN_TIMEOUT.name(), RUN_TIMEOUT_ALARM_KEYS); ALARM_KEYS.put(QUEUE_TIMEOUT.name(), QUEUE_TIMEOUT_ALARM_KEYS); + ALARM_KEYS.put(PIN_TIMEOUT.name(), PIN_TIMEOUT_ALARM_KEYS); ALL_ALARM_KEYS = ALARM_KEYS.values().stream().flatMap(Collection::stream).collect(Collectors.toSet()); ALL_ALARM_KEYS.addAll(COMMON_ALARM_KEYS); @@ -161,6 +161,23 @@ public static void initNotify(DtpExecutor executor) { AlarmManager.initAlarm(executor.getThreadPoolName(), executor.getNotifyItems()); } + public static void initNotify(VirtualThreadExecutorProxy executor) { + val dtpProperties = ContextManagerHelper.getBean(DtpProperties.class); + val platforms = dtpProperties.getPlatforms(); + if (CollectionUtils.isEmpty(platforms)) { + executor.setNotifyItems(Lists.newArrayList()); + executor.setPlatformIds(Lists.newArrayList()); + log.warn("DynamicTp notify, no notify platforms configured for [{}]", executor.getThreadPoolName()); + return; + } + if (CollectionUtils.isEmpty(executor.getNotifyItems())) { + log.warn("DynamicTp notify, no notify items configured for [{}]", executor.getThreadPoolName()); + return; + } + fillPlatforms(executor.getPlatformIds(), platforms, executor.getNotifyItems()); + AlarmManager.initAlarm(executor.getThreadPoolName(), executor.getNotifyItems()); + } + public static void updateNotifyInfo(ExecutorWrapper executorWrapper, TpExecutorProps props, List platforms) { diff --git a/core/src/main/java/org/dromara/dynamictp/core/support/ThreadPoolStatProvider.java b/core/src/main/java/org/dromara/dynamictp/core/support/ExecutorStatProvider.java similarity index 96% rename from core/src/main/java/org/dromara/dynamictp/core/support/ThreadPoolStatProvider.java rename to core/src/main/java/org/dromara/dynamictp/core/support/ExecutorStatProvider.java index a4488b92d..981194133 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/support/ThreadPoolStatProvider.java +++ b/core/src/main/java/org/dromara/dynamictp/core/support/ExecutorStatProvider.java @@ -39,7 +39,7 @@ * @author hanli * @since 1.1.4 */ -public class ThreadPoolStatProvider { +public class ExecutorStatProvider { private final ExecutorWrapper executorWrapper; @@ -93,12 +93,12 @@ public class ThreadPoolStatProvider { */ private final PerformanceProvider performanceProvider = new PerformanceProvider(); - private ThreadPoolStatProvider(ExecutorWrapper executorWrapper) { + private ExecutorStatProvider(ExecutorWrapper executorWrapper) { this.executorWrapper = executorWrapper; } - public static ThreadPoolStatProvider of(ExecutorWrapper executorWrapper) { - val provider = new ThreadPoolStatProvider(executorWrapper); + public static ExecutorStatProvider of(ExecutorWrapper executorWrapper) { + val provider = new ExecutorStatProvider(executorWrapper); if (executorWrapper.isDtpExecutor()) { val dtpExecutor = (DtpExecutor) executorWrapper.getExecutor(); provider.setRunTimeout(dtpExecutor.getRunTimeout()); diff --git a/core/src/main/java/org/dromara/dynamictp/core/support/ExecutorWrapper.java b/core/src/main/java/org/dromara/dynamictp/core/support/ExecutorWrapper.java index 8e6cc5fc0..5ef7a9f60 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/support/ExecutorWrapper.java +++ b/core/src/main/java/org/dromara/dynamictp/core/support/ExecutorWrapper.java @@ -28,6 +28,7 @@ import org.dromara.dynamictp.core.notifier.capture.CapturedExecutor; import org.dromara.dynamictp.core.notifier.manager.AlarmManager; import org.dromara.dynamictp.core.reject.RejectHandlerGetter; +import org.dromara.dynamictp.core.support.adapter.VirtualThreadExecutorAdapter; import org.dromara.dynamictp.core.support.proxy.VirtualThreadExecutorProxy; import org.dromara.dynamictp.core.support.adapter.ExecutorAdapter; import org.dromara.dynamictp.core.support.adapter.ThreadPoolExecutorAdapter; @@ -104,9 +105,9 @@ public class ExecutorWrapper { protected int awaitTerminationSeconds = 0; /** - * Thread pool stat provider + * Executor stat provider */ - private ThreadPoolStatProvider threadPoolStatProvider; + private ExecutorStatProvider executorStatProvider; private ExecutorWrapper() { } @@ -127,7 +128,7 @@ public ExecutorWrapper(DtpExecutor executor) { this.rejectEnhanced = executor.isRejectEnhanced(); this.waitForTasksToCompleteOnShutdown = executor.isWaitForTasksToCompleteOnShutdown(); this.awaitTerminationSeconds = executor.getAwaitTerminationSeconds(); - this.threadPoolStatProvider = ThreadPoolStatProvider.of(this); + this.executorStatProvider = ExecutorStatProvider.of(this); } /** @@ -140,16 +141,23 @@ public ExecutorWrapper(String threadPoolName, Executor executor) { this.threadPoolName = threadPoolName; if (executor instanceof ThreadPoolExecutor) { this.executor = new ThreadPoolExecutorAdapter((ThreadPoolExecutor) executor); + this.notifyItems = NotifyItem.getAllNotifyItems(); } else if (executor instanceof ExecutorAdapter) { this.executor = (ExecutorAdapter) executor; + this.notifyItems = NotifyItem.getAllNotifyItems(); } else if (executor instanceof VirtualThreadExecutorProxy) { - this.executor = new VirtualThreadExecutorAdapter(((VirtualThreadExecutorProxy) executor).getThreadPerTaskExecutor()); + this.executor = new VirtualThreadExecutorAdapter(executor); + this.threadPoolAliasName = ((VirtualThreadExecutorProxy) executor).getThreadPoolAliasName(); + this.notifyItems = ((VirtualThreadExecutorProxy) executor).getNotifyItems(); + this.notifyEnabled = ((VirtualThreadExecutorProxy) executor).isNotifyEnabled(); + this.platformIds = ((VirtualThreadExecutorProxy) executor).getPlatformIds(); + this.awareNames = ((VirtualThreadExecutorProxy) executor).getAwareNames(); + this.executorStatProvider = ExecutorStatProvider.of(this); } else { throw new IllegalArgumentException("unsupported Executor type !"); } - this.notifyItems = NotifyItem.getAllNotifyItems(); AlarmManager.initAlarm(threadPoolName, notifyItems); - this.threadPoolStatProvider = ThreadPoolStatProvider.of(this); + this.executorStatProvider = ExecutorStatProvider.of(this); } /** @@ -180,7 +188,10 @@ public void initialize() { if (isDtpExecutor()) { ((DtpExecutor) getExecutor()).initialize(); AwareManager.register(this); - } else if (isThreadPoolExecutor() || isVirtualThreadExecutor()) { + } else if (isVirtualThreadExecutor()) { + ((VirtualThreadExecutorProxy) getExecutor().getOriginal()).initialize(); + AwareManager.register(this); + } else if (isThreadPoolExecutor()) { AwareManager.register(this); } } @@ -213,7 +224,8 @@ public boolean isThreadPoolExecutor() { * @return boolean */ public boolean isVirtualThreadExecutor() { - return this.executor instanceof VirtualThreadExecutorAdapter; + return this.executor instanceof VirtualThreadExecutorAdapter + || this.executor.getOriginal() instanceof VirtualThreadExecutorAdapter; } /** diff --git a/core/src/main/java/org/dromara/dynamictp/core/support/VirtualThreadExecutorAdapter.java b/core/src/main/java/org/dromara/dynamictp/core/support/adapter/VirtualThreadExecutorAdapter.java similarity index 95% rename from core/src/main/java/org/dromara/dynamictp/core/support/VirtualThreadExecutorAdapter.java rename to core/src/main/java/org/dromara/dynamictp/core/support/adapter/VirtualThreadExecutorAdapter.java index 6d3a2dff6..54dea40e9 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/support/VirtualThreadExecutorAdapter.java +++ b/core/src/main/java/org/dromara/dynamictp/core/support/adapter/VirtualThreadExecutorAdapter.java @@ -14,9 +14,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.dromara.dynamictp.core.support; - -import org.dromara.dynamictp.core.support.adapter.ExecutorAdapter; +package org.dromara.dynamictp.core.support.adapter; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; diff --git a/core/src/main/java/org/dromara/dynamictp/core/support/proxy/VirtualThreadExecutorProxy.java b/core/src/main/java/org/dromara/dynamictp/core/support/proxy/VirtualThreadExecutorProxy.java index 906d3b4c0..3938f9a51 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/support/proxy/VirtualThreadExecutorProxy.java +++ b/core/src/main/java/org/dromara/dynamictp/core/support/proxy/VirtualThreadExecutorProxy.java @@ -22,6 +22,7 @@ import org.dromara.dynamictp.common.entity.NotifyItem; import org.dromara.dynamictp.core.aware.AwareManager; import org.dromara.dynamictp.core.aware.TaskEnhanceAware; +import org.dromara.dynamictp.core.notifier.manager.NotifyHelper; import org.dromara.dynamictp.core.support.task.runnable.EnhancedRunnable; import org.dromara.dynamictp.core.support.task.wrapper.TaskWrapper; @@ -70,6 +71,11 @@ public class VirtualThreadExecutorProxy implements TaskEnhanceAware, ExecutorSer */ private String threadPoolAliasName; + /** + * Current pinned duration. + */ + private long curPinDuration = 0; + /** * If enable notify. */ @@ -78,7 +84,7 @@ public class VirtualThreadExecutorProxy implements TaskEnhanceAware, ExecutorSer /** * Notify items, see {@link NotifyItemEnum}. */ - private List notifyItems; + private List notifyItems = NotifyItem.getAllNotifyItems(); /** * Plugin names. @@ -190,6 +196,10 @@ public T invokeAny(Collection> collection, long l, Tim return threadPerTaskExecutor.invokeAny(collection, l, timeUnit); } + public void initialize() { + NotifyHelper.initNotify(this); + } + public String getThreadPoolName() { return threadPoolName; } @@ -245,4 +255,13 @@ public List getNotifyItems() { public void setNotifyItems(List notifyItems) { this.notifyItems = notifyItems; } + + public long getCurPinDuration() { + return curPinDuration; + } + + public void setCurPinDuration(long curPinDuration) { + this.curPinDuration = curPinDuration; + } + } diff --git a/core/src/main/java/org/dromara/dynamictp/core/timer/AbstractTimeoutTimerTask.java b/core/src/main/java/org/dromara/dynamictp/core/timer/AbstractTimeoutTimerTask.java index 160e25140..8ba4a2ebd 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/timer/AbstractTimeoutTimerTask.java +++ b/core/src/main/java/org/dromara/dynamictp/core/timer/AbstractTimeoutTimerTask.java @@ -46,7 +46,7 @@ protected AbstractTimeoutTimerTask(ExecutorWrapper executorWrapper, Runnable run @Override public void run(Timeout timeout) throws Exception { - val statProvider = executorWrapper.getThreadPoolStatProvider(); + val statProvider = executorWrapper.getExecutorStatProvider(); if (Objects.isNull(statProvider)) { return; } diff --git a/core/src/main/java/org/dromara/dynamictp/core/timer/QueueTimeoutTimerTask.java b/core/src/main/java/org/dromara/dynamictp/core/timer/QueueTimeoutTimerTask.java index 2bbb82a3c..36c3f0059 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/timer/QueueTimeoutTimerTask.java +++ b/core/src/main/java/org/dromara/dynamictp/core/timer/QueueTimeoutTimerTask.java @@ -40,7 +40,7 @@ public QueueTimeoutTimerTask(ExecutorWrapper executorWrapper, Runnable runnable) @Override protected void doRun() { - val statProvider = executorWrapper.getThreadPoolStatProvider(); + val statProvider = executorWrapper.getExecutorStatProvider(); ExecutorAdapter executor = statProvider.getExecutorWrapper().getExecutor(); val pair = getTaskNameAndTraceId(); statProvider.incQueueTimeoutCount(1); diff --git a/core/src/main/java/org/dromara/dynamictp/core/timer/RunTimeoutTimerTask.java b/core/src/main/java/org/dromara/dynamictp/core/timer/RunTimeoutTimerTask.java index 3bf958a38..e343edbc6 100644 --- a/core/src/main/java/org/dromara/dynamictp/core/timer/RunTimeoutTimerTask.java +++ b/core/src/main/java/org/dromara/dynamictp/core/timer/RunTimeoutTimerTask.java @@ -43,7 +43,7 @@ public RunTimeoutTimerTask(ExecutorWrapper executorWrapper, Runnable runnable, T @Override protected void doRun() { - val statProvider = executorWrapper.getThreadPoolStatProvider(); + val statProvider = executorWrapper.getExecutorStatProvider(); ExecutorAdapter executor = statProvider.getExecutorWrapper().getExecutor(); val pair = getTaskNameAndTraceId(); statProvider.incRunTimeoutCount(1); diff --git a/example/example-apollo/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java b/example/example-apollo/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java index 761568164..e17ee3556 100644 --- a/example/example-apollo/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java +++ b/example/example-apollo/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java @@ -52,6 +52,11 @@ protected String getAlarmTemplate() { return SmsNotifyConst.SMS_ALARM_TEMPLATE; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{SmsNotifyConst.SMS_ALARM_TEMPLATE_PREFIX, SmsNotifyConst.SMS_ALARM_COMMON_TEMPLATE.repeat(Math.max(0, num)), SmsNotifyConst.SMS_ALARM_TEMPLATE_SUFFIX}; + } + @Override protected Pair getColors() { return null; diff --git a/example/example-apollo/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java b/example/example-apollo/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java index 505ea7c13..820caeadf 100644 --- a/example/example-apollo/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java +++ b/example/example-apollo/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java @@ -27,13 +27,26 @@ public class SmsNotifyConst { private SmsNotifyConst() { } - public static final String SMS_ALARM_TEMPLATE = + public static final String SMS_ALARM_TEMPLATE_PREFIX = "服务名称:%s \n" + "实例信息:%s \n" + "环境:%s \n" + "线程池名称:%s \n" + "报警项:%s \n" + - "报警阈值 / 当前值:%s \n" + + "报警阈值 / 当前值:%s \n"; + + public static final String SMS_ALARM_COMMON_TEMPLATE = "%s \n"; + + public static final String SMS_ALARM_TEMPLATE_SUFFIX = + "上次报警时间:%s \n" + + "报警时间:%s \n" + + "接收人:@%s \n" + + "trace 信息:%s \n" + + "报警间隔:%ss \n" + + "扩展信息:%s \n"; + + public static final String SMS_ALARM_TEMPLATE = + SMS_ALARM_TEMPLATE_PREFIX + "核心线程数:%s \n" + "最大线程数:%s \n" + "当前线程数:%s \n" + @@ -50,12 +63,7 @@ private SmsNotifyConst() { } "总拒绝任务数量:%s \n" + "总执行超时任务数量:%s \n" + "总等待超时任务数量:%s \n" + - "上次报警时间:%s \n" + - "报警时间:%s \n" + - "接收人:@%s \n" + - "trace 信息:%s \n" + - "报警间隔:%ss \n" + - "扩展信息:%s \n"; + SMS_ALARM_TEMPLATE_SUFFIX; public static final String SMS_NOTICE_TEMPLATE = "服务名称:%s \n" + diff --git a/example/example-consul-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java b/example/example-consul-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java index 761568164..e17ee3556 100644 --- a/example/example-consul-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java +++ b/example/example-consul-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java @@ -52,6 +52,11 @@ protected String getAlarmTemplate() { return SmsNotifyConst.SMS_ALARM_TEMPLATE; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{SmsNotifyConst.SMS_ALARM_TEMPLATE_PREFIX, SmsNotifyConst.SMS_ALARM_COMMON_TEMPLATE.repeat(Math.max(0, num)), SmsNotifyConst.SMS_ALARM_TEMPLATE_SUFFIX}; + } + @Override protected Pair getColors() { return null; diff --git a/example/example-consul-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java b/example/example-consul-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java index 505ea7c13..a2588c47f 100644 --- a/example/example-consul-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java +++ b/example/example-consul-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java @@ -27,13 +27,26 @@ public class SmsNotifyConst { private SmsNotifyConst() { } - public static final String SMS_ALARM_TEMPLATE = + public static final String SMS_ALARM_TEMPLATE_PREFIX = "服务名称:%s \n" + "实例信息:%s \n" + "环境:%s \n" + "线程池名称:%s \n" + "报警项:%s \n" + - "报警阈值 / 当前值:%s \n" + + "报警阈值 / 当前值:%s \n"; + + public static final String SMS_ALARM_COMMON_TEMPLATE = "%s \n"; + + public static final String SMS_ALARM_TEMPLATE_SUFFIX = + "上次报警时间:%s \n" + + "报警时间:%s \n" + + "接收人:@%s \n" + + "trace 信息:%s \n" + + "报警间隔:%ss \n" + + "扩展信息:%s \n"; + + public static final String SMS_ALARM_TEMPLATE = + SMS_ALARM_TEMPLATE_PREFIX + "核心线程数:%s \n" + "最大线程数:%s \n" + "当前线程数:%s \n" + @@ -50,12 +63,7 @@ private SmsNotifyConst() { } "总拒绝任务数量:%s \n" + "总执行超时任务数量:%s \n" + "总等待超时任务数量:%s \n" + - "上次报警时间:%s \n" + - "报警时间:%s \n" + - "接收人:@%s \n" + - "trace 信息:%s \n" + - "报警间隔:%ss \n" + - "扩展信息:%s \n"; + SMS_ALARM_TEMPLATE_SUFFIX; public static final String SMS_NOTICE_TEMPLATE = "服务名称:%s \n" + diff --git a/example/example-etcd/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java b/example/example-etcd/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java index 761568164..e17ee3556 100644 --- a/example/example-etcd/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java +++ b/example/example-etcd/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java @@ -52,6 +52,11 @@ protected String getAlarmTemplate() { return SmsNotifyConst.SMS_ALARM_TEMPLATE; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{SmsNotifyConst.SMS_ALARM_TEMPLATE_PREFIX, SmsNotifyConst.SMS_ALARM_COMMON_TEMPLATE.repeat(Math.max(0, num)), SmsNotifyConst.SMS_ALARM_TEMPLATE_SUFFIX}; + } + @Override protected Pair getColors() { return null; diff --git a/example/example-etcd/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java b/example/example-etcd/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java index 505ea7c13..a2588c47f 100644 --- a/example/example-etcd/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java +++ b/example/example-etcd/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java @@ -27,13 +27,26 @@ public class SmsNotifyConst { private SmsNotifyConst() { } - public static final String SMS_ALARM_TEMPLATE = + public static final String SMS_ALARM_TEMPLATE_PREFIX = "服务名称:%s \n" + "实例信息:%s \n" + "环境:%s \n" + "线程池名称:%s \n" + "报警项:%s \n" + - "报警阈值 / 当前值:%s \n" + + "报警阈值 / 当前值:%s \n"; + + public static final String SMS_ALARM_COMMON_TEMPLATE = "%s \n"; + + public static final String SMS_ALARM_TEMPLATE_SUFFIX = + "上次报警时间:%s \n" + + "报警时间:%s \n" + + "接收人:@%s \n" + + "trace 信息:%s \n" + + "报警间隔:%ss \n" + + "扩展信息:%s \n"; + + public static final String SMS_ALARM_TEMPLATE = + SMS_ALARM_TEMPLATE_PREFIX + "核心线程数:%s \n" + "最大线程数:%s \n" + "当前线程数:%s \n" + @@ -50,12 +63,7 @@ private SmsNotifyConst() { } "总拒绝任务数量:%s \n" + "总执行超时任务数量:%s \n" + "总等待超时任务数量:%s \n" + - "上次报警时间:%s \n" + - "报警时间:%s \n" + - "接收人:@%s \n" + - "trace 信息:%s \n" + - "报警间隔:%ss \n" + - "扩展信息:%s \n"; + SMS_ALARM_TEMPLATE_SUFFIX; public static final String SMS_NOTICE_TEMPLATE = "服务名称:%s \n" + diff --git a/example/example-huawei-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java b/example/example-huawei-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java index 761568164..e17ee3556 100644 --- a/example/example-huawei-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java +++ b/example/example-huawei-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java @@ -52,6 +52,11 @@ protected String getAlarmTemplate() { return SmsNotifyConst.SMS_ALARM_TEMPLATE; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{SmsNotifyConst.SMS_ALARM_TEMPLATE_PREFIX, SmsNotifyConst.SMS_ALARM_COMMON_TEMPLATE.repeat(Math.max(0, num)), SmsNotifyConst.SMS_ALARM_TEMPLATE_SUFFIX}; + } + @Override protected Pair getColors() { return null; diff --git a/example/example-huawei-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java b/example/example-huawei-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java index 505ea7c13..a2588c47f 100644 --- a/example/example-huawei-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java +++ b/example/example-huawei-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java @@ -27,13 +27,26 @@ public class SmsNotifyConst { private SmsNotifyConst() { } - public static final String SMS_ALARM_TEMPLATE = + public static final String SMS_ALARM_TEMPLATE_PREFIX = "服务名称:%s \n" + "实例信息:%s \n" + "环境:%s \n" + "线程池名称:%s \n" + "报警项:%s \n" + - "报警阈值 / 当前值:%s \n" + + "报警阈值 / 当前值:%s \n"; + + public static final String SMS_ALARM_COMMON_TEMPLATE = "%s \n"; + + public static final String SMS_ALARM_TEMPLATE_SUFFIX = + "上次报警时间:%s \n" + + "报警时间:%s \n" + + "接收人:@%s \n" + + "trace 信息:%s \n" + + "报警间隔:%ss \n" + + "扩展信息:%s \n"; + + public static final String SMS_ALARM_TEMPLATE = + SMS_ALARM_TEMPLATE_PREFIX + "核心线程数:%s \n" + "最大线程数:%s \n" + "当前线程数:%s \n" + @@ -50,12 +63,7 @@ private SmsNotifyConst() { } "总拒绝任务数量:%s \n" + "总执行超时任务数量:%s \n" + "总等待超时任务数量:%s \n" + - "上次报警时间:%s \n" + - "报警时间:%s \n" + - "接收人:@%s \n" + - "trace 信息:%s \n" + - "报警间隔:%ss \n" + - "扩展信息:%s \n"; + SMS_ALARM_TEMPLATE_SUFFIX; public static final String SMS_NOTICE_TEMPLATE = "服务名称:%s \n" + diff --git a/example/example-nacos-cloud/pom.xml b/example/example-nacos-cloud/pom.xml index 22490e3b1..a2baf0fb6 100644 --- a/example/example-nacos-cloud/pom.xml +++ b/example/example-nacos-cloud/pom.xml @@ -20,7 +20,7 @@ com.alibaba.cloud spring-cloud-alibaba-dependencies - 2021.1 + 2022.0.0.0 pom import @@ -89,4 +89,16 @@ spring-boot-starter-data-redis - \ No newline at end of file + + + + org.apache.maven.plugins + maven-compiler-plugin + + 21 + 21 + + + + + diff --git a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java index 761568164..e17ee3556 100644 --- a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java +++ b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java @@ -52,6 +52,11 @@ protected String getAlarmTemplate() { return SmsNotifyConst.SMS_ALARM_TEMPLATE; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{SmsNotifyConst.SMS_ALARM_TEMPLATE_PREFIX, SmsNotifyConst.SMS_ALARM_COMMON_TEMPLATE.repeat(Math.max(0, num)), SmsNotifyConst.SMS_ALARM_TEMPLATE_SUFFIX}; + } + @Override protected Pair getColors() { return null; diff --git a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java index 505ea7c13..a2588c47f 100644 --- a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java +++ b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java @@ -27,13 +27,26 @@ public class SmsNotifyConst { private SmsNotifyConst() { } - public static final String SMS_ALARM_TEMPLATE = + public static final String SMS_ALARM_TEMPLATE_PREFIX = "服务名称:%s \n" + "实例信息:%s \n" + "环境:%s \n" + "线程池名称:%s \n" + "报警项:%s \n" + - "报警阈值 / 当前值:%s \n" + + "报警阈值 / 当前值:%s \n"; + + public static final String SMS_ALARM_COMMON_TEMPLATE = "%s \n"; + + public static final String SMS_ALARM_TEMPLATE_SUFFIX = + "上次报警时间:%s \n" + + "报警时间:%s \n" + + "接收人:@%s \n" + + "trace 信息:%s \n" + + "报警间隔:%ss \n" + + "扩展信息:%s \n"; + + public static final String SMS_ALARM_TEMPLATE = + SMS_ALARM_TEMPLATE_PREFIX + "核心线程数:%s \n" + "最大线程数:%s \n" + "当前线程数:%s \n" + @@ -50,12 +63,7 @@ private SmsNotifyConst() { } "总拒绝任务数量:%s \n" + "总执行超时任务数量:%s \n" + "总等待超时任务数量:%s \n" + - "上次报警时间:%s \n" + - "报警时间:%s \n" + - "接收人:@%s \n" + - "trace 信息:%s \n" + - "报警间隔:%ss \n" + - "扩展信息:%s \n"; + SMS_ALARM_TEMPLATE_SUFFIX; public static final String SMS_NOTICE_TEMPLATE = "服务名称:%s \n" + diff --git a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java index 1c7b49f2a..4342dac02 100644 --- a/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java +++ b/example/example-nacos-cloud/src/main/java/org/dromara/dynamictp/example/service/impl/TestServiceImpl.java @@ -30,6 +30,7 @@ import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor; import org.springframework.stereotype.Service; +import java.time.Duration; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; @@ -63,7 +64,7 @@ public TestServiceImpl(ThreadPoolExecutor jucThreadPoolExecutor, DtpExecutor eagerDtpExecutor, ScheduledExecutorService scheduledDtpExecutor, OrderedDtpExecutor orderedDtpExecutor, - @Qualifier("virtualThreadExecutor") ExecutorService virtualThreadExecutor) { + @Qualifier("virtualThreadExecutor1") ExecutorService virtualThreadExecutor) { this.jucThreadPoolExecutor = jucThreadPoolExecutor; this.threadPoolTaskExecutor = threadPoolTaskExecutor; this.eagerDtpExecutor = eagerDtpExecutor; @@ -153,11 +154,20 @@ public void testVTExecutor() { for (int i = 0; i < 10; i++) { int finalI = i; virtualThreadExecutor.execute(() -> { - log.info("i am a VTExecutor's {} task", finalI); - try { - Thread.sleep(30000); - } catch (InterruptedException e) { - throw new RuntimeException(e); +// log.info("i am a VTExecutor's {} task", finalI); +// try { +// Thread.sleep(30000); +// } catch (InterruptedException e) { +// throw new RuntimeException(e); +// } + synchronized (this) { + log.info("i am a VTExecutor's {} task", finalI); + log.info("Causing thread pinning for example purposes"); + try { + Thread.sleep(Duration.ofMillis(4000)); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } } }); } diff --git a/example/example-nacos/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java b/example/example-nacos/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java index 761568164..e17ee3556 100644 --- a/example/example-nacos/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java +++ b/example/example-nacos/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java @@ -52,6 +52,11 @@ protected String getAlarmTemplate() { return SmsNotifyConst.SMS_ALARM_TEMPLATE; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{SmsNotifyConst.SMS_ALARM_TEMPLATE_PREFIX, SmsNotifyConst.SMS_ALARM_COMMON_TEMPLATE.repeat(Math.max(0, num)), SmsNotifyConst.SMS_ALARM_TEMPLATE_SUFFIX}; + } + @Override protected Pair getColors() { return null; diff --git a/example/example-nacos/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java b/example/example-nacos/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java index 505ea7c13..a2588c47f 100644 --- a/example/example-nacos/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java +++ b/example/example-nacos/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java @@ -27,13 +27,26 @@ public class SmsNotifyConst { private SmsNotifyConst() { } - public static final String SMS_ALARM_TEMPLATE = + public static final String SMS_ALARM_TEMPLATE_PREFIX = "服务名称:%s \n" + "实例信息:%s \n" + "环境:%s \n" + "线程池名称:%s \n" + "报警项:%s \n" + - "报警阈值 / 当前值:%s \n" + + "报警阈值 / 当前值:%s \n"; + + public static final String SMS_ALARM_COMMON_TEMPLATE = "%s \n"; + + public static final String SMS_ALARM_TEMPLATE_SUFFIX = + "上次报警时间:%s \n" + + "报警时间:%s \n" + + "接收人:@%s \n" + + "trace 信息:%s \n" + + "报警间隔:%ss \n" + + "扩展信息:%s \n"; + + public static final String SMS_ALARM_TEMPLATE = + SMS_ALARM_TEMPLATE_PREFIX + "核心线程数:%s \n" + "最大线程数:%s \n" + "当前线程数:%s \n" + @@ -50,12 +63,7 @@ private SmsNotifyConst() { } "总拒绝任务数量:%s \n" + "总执行超时任务数量:%s \n" + "总等待超时任务数量:%s \n" + - "上次报警时间:%s \n" + - "报警时间:%s \n" + - "接收人:@%s \n" + - "trace 信息:%s \n" + - "报警间隔:%ss \n" + - "扩展信息:%s \n"; + SMS_ALARM_TEMPLATE_SUFFIX; public static final String SMS_NOTICE_TEMPLATE = "服务名称:%s \n" + diff --git a/example/example-polaris-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java b/example/example-polaris-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java index 761568164..e17ee3556 100644 --- a/example/example-polaris-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java +++ b/example/example-polaris-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java @@ -52,6 +52,11 @@ protected String getAlarmTemplate() { return SmsNotifyConst.SMS_ALARM_TEMPLATE; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{SmsNotifyConst.SMS_ALARM_TEMPLATE_PREFIX, SmsNotifyConst.SMS_ALARM_COMMON_TEMPLATE.repeat(Math.max(0, num)), SmsNotifyConst.SMS_ALARM_TEMPLATE_SUFFIX}; + } + @Override protected Pair getColors() { return null; diff --git a/example/example-polaris-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java b/example/example-polaris-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java index 505ea7c13..a2588c47f 100644 --- a/example/example-polaris-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java +++ b/example/example-polaris-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java @@ -27,13 +27,26 @@ public class SmsNotifyConst { private SmsNotifyConst() { } - public static final String SMS_ALARM_TEMPLATE = + public static final String SMS_ALARM_TEMPLATE_PREFIX = "服务名称:%s \n" + "实例信息:%s \n" + "环境:%s \n" + "线程池名称:%s \n" + "报警项:%s \n" + - "报警阈值 / 当前值:%s \n" + + "报警阈值 / 当前值:%s \n"; + + public static final String SMS_ALARM_COMMON_TEMPLATE = "%s \n"; + + public static final String SMS_ALARM_TEMPLATE_SUFFIX = + "上次报警时间:%s \n" + + "报警时间:%s \n" + + "接收人:@%s \n" + + "trace 信息:%s \n" + + "报警间隔:%ss \n" + + "扩展信息:%s \n"; + + public static final String SMS_ALARM_TEMPLATE = + SMS_ALARM_TEMPLATE_PREFIX + "核心线程数:%s \n" + "最大线程数:%s \n" + "当前线程数:%s \n" + @@ -50,12 +63,7 @@ private SmsNotifyConst() { } "总拒绝任务数量:%s \n" + "总执行超时任务数量:%s \n" + "总等待超时任务数量:%s \n" + - "上次报警时间:%s \n" + - "报警时间:%s \n" + - "接收人:@%s \n" + - "trace 信息:%s \n" + - "报警间隔:%ss \n" + - "扩展信息:%s \n"; + SMS_ALARM_TEMPLATE_SUFFIX; public static final String SMS_NOTICE_TEMPLATE = "服务名称:%s \n" + diff --git a/example/example-zookeeper-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java b/example/example-zookeeper-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java index 761568164..e17ee3556 100644 --- a/example/example-zookeeper-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java +++ b/example/example-zookeeper-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java @@ -52,6 +52,11 @@ protected String getAlarmTemplate() { return SmsNotifyConst.SMS_ALARM_TEMPLATE; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{SmsNotifyConst.SMS_ALARM_TEMPLATE_PREFIX, SmsNotifyConst.SMS_ALARM_COMMON_TEMPLATE.repeat(Math.max(0, num)), SmsNotifyConst.SMS_ALARM_TEMPLATE_SUFFIX}; + } + @Override protected Pair getColors() { return null; diff --git a/example/example-zookeeper-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java b/example/example-zookeeper-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java index 505ea7c13..a2588c47f 100644 --- a/example/example-zookeeper-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java +++ b/example/example-zookeeper-cloud/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java @@ -27,13 +27,26 @@ public class SmsNotifyConst { private SmsNotifyConst() { } - public static final String SMS_ALARM_TEMPLATE = + public static final String SMS_ALARM_TEMPLATE_PREFIX = "服务名称:%s \n" + "实例信息:%s \n" + "环境:%s \n" + "线程池名称:%s \n" + "报警项:%s \n" + - "报警阈值 / 当前值:%s \n" + + "报警阈值 / 当前值:%s \n"; + + public static final String SMS_ALARM_COMMON_TEMPLATE = "%s \n"; + + public static final String SMS_ALARM_TEMPLATE_SUFFIX = + "上次报警时间:%s \n" + + "报警时间:%s \n" + + "接收人:@%s \n" + + "trace 信息:%s \n" + + "报警间隔:%ss \n" + + "扩展信息:%s \n"; + + public static final String SMS_ALARM_TEMPLATE = + SMS_ALARM_TEMPLATE_PREFIX + "核心线程数:%s \n" + "最大线程数:%s \n" + "当前线程数:%s \n" + @@ -50,12 +63,7 @@ private SmsNotifyConst() { } "总拒绝任务数量:%s \n" + "总执行超时任务数量:%s \n" + "总等待超时任务数量:%s \n" + - "上次报警时间:%s \n" + - "报警时间:%s \n" + - "接收人:@%s \n" + - "trace 信息:%s \n" + - "报警间隔:%ss \n" + - "扩展信息:%s \n"; + SMS_ALARM_TEMPLATE_SUFFIX; public static final String SMS_NOTICE_TEMPLATE = "服务名称:%s \n" + diff --git a/example/example-zookeeper/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java b/example/example-zookeeper/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java index 761568164..e17ee3556 100644 --- a/example/example-zookeeper/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java +++ b/example/example-zookeeper/src/main/java/org/dromara/dynamictp/example/notifier/SmsDtpNotifier.java @@ -52,6 +52,11 @@ protected String getAlarmTemplate() { return SmsNotifyConst.SMS_ALARM_TEMPLATE; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{SmsNotifyConst.SMS_ALARM_TEMPLATE_PREFIX, SmsNotifyConst.SMS_ALARM_COMMON_TEMPLATE.repeat(Math.max(0, num)), SmsNotifyConst.SMS_ALARM_TEMPLATE_SUFFIX}; + } + @Override protected Pair getColors() { return null; diff --git a/example/example-zookeeper/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java b/example/example-zookeeper/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java index 505ea7c13..a2588c47f 100644 --- a/example/example-zookeeper/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java +++ b/example/example-zookeeper/src/main/java/org/dromara/dynamictp/example/notifier/SmsNotifyConst.java @@ -27,13 +27,26 @@ public class SmsNotifyConst { private SmsNotifyConst() { } - public static final String SMS_ALARM_TEMPLATE = + public static final String SMS_ALARM_TEMPLATE_PREFIX = "服务名称:%s \n" + "实例信息:%s \n" + "环境:%s \n" + "线程池名称:%s \n" + "报警项:%s \n" + - "报警阈值 / 当前值:%s \n" + + "报警阈值 / 当前值:%s \n"; + + public static final String SMS_ALARM_COMMON_TEMPLATE = "%s \n"; + + public static final String SMS_ALARM_TEMPLATE_SUFFIX = + "上次报警时间:%s \n" + + "报警时间:%s \n" + + "接收人:@%s \n" + + "trace 信息:%s \n" + + "报警间隔:%ss \n" + + "扩展信息:%s \n"; + + public static final String SMS_ALARM_TEMPLATE = + SMS_ALARM_TEMPLATE_PREFIX + "核心线程数:%s \n" + "最大线程数:%s \n" + "当前线程数:%s \n" + @@ -50,12 +63,7 @@ private SmsNotifyConst() { } "总拒绝任务数量:%s \n" + "总执行超时任务数量:%s \n" + "总等待超时任务数量:%s \n" + - "上次报警时间:%s \n" + - "报警时间:%s \n" + - "接收人:@%s \n" + - "trace 信息:%s \n" + - "报警间隔:%ss \n" + - "扩展信息:%s \n"; + SMS_ALARM_TEMPLATE_SUFFIX; public static final String SMS_NOTICE_TEMPLATE = "服务名称:%s \n" + diff --git a/extension/extension-notify-email/src/main/java/org/dromara/dynamictp/extension/notify/email/DtpEmailNotifier.java b/extension/extension-notify-email/src/main/java/org/dromara/dynamictp/extension/notify/email/DtpEmailNotifier.java index ca1aa3049..d32ba1cac 100644 --- a/extension/extension-notify-email/src/main/java/org/dromara/dynamictp/extension/notify/email/DtpEmailNotifier.java +++ b/extension/extension-notify-email/src/main/java/org/dromara/dynamictp/extension/notify/email/DtpEmailNotifier.java @@ -72,6 +72,11 @@ protected String getAlarmTemplate() { return null; } + @Override + protected String[] getCommonAlarmTemplate(int length) { + return null; + } + @Override protected Pair getColors() { return null; @@ -84,7 +89,7 @@ protected String buildAlarmContent(NotifyPlatform platform, NotifyItemEnum notif val executor = executorWrapper.getExecutor(); NotifyItem notifyItem = alarmCtx.getNotifyItem(); AlarmInfo alarmInfo = alarmCtx.getAlarmInfo(); - val statProvider = executorWrapper.getThreadPoolStatProvider(); + val statProvider = executorWrapper.getExecutorStatProvider(); val alarmValue = notifyItem.getThreshold() + notifyItemEnum.getUnit() + " / " + AlarmCounter.calcCurrentValue(executorWrapper, notifyItemEnum) + notifyItemEnum.getUnit(); diff --git a/extension/extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/extension/notify/yunzhijia/DtpYunZhiJiaNotifier.java b/extension/extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/extension/notify/yunzhijia/DtpYunZhiJiaNotifier.java index fa6ce1da2..0b734e26e 100644 --- a/extension/extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/extension/notify/yunzhijia/DtpYunZhiJiaNotifier.java +++ b/extension/extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/extension/notify/yunzhijia/DtpYunZhiJiaNotifier.java @@ -51,6 +51,11 @@ protected String getAlarmTemplate() { return YunZhiJiaNotifyConst.ALARM_TEMPLATE; } + @Override + protected String[] getCommonAlarmTemplate(int num) { + return new String[]{YunZhiJiaNotifyConst.ALARM_TEMPLATE_PREFIX, YunZhiJiaNotifyConst.ALARM_COMMON_TEMPLATE.repeat(Math.max(0, num)), YunZhiJiaNotifyConst.ALARM_TEMPLATE_SUFFIX}; + } + @Override protected Pair getColors() { return new ImmutablePair<>(YunZhiJiaNotifyConst.WARNING_COLOR, YunZhiJiaNotifyConst.COMMENT_COLOR); diff --git a/extension/extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/extension/notify/yunzhijia/YunZhiJiaNotifyConst.java b/extension/extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/extension/notify/yunzhijia/YunZhiJiaNotifyConst.java index c3d957fc7..3028e8489 100644 --- a/extension/extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/extension/notify/yunzhijia/YunZhiJiaNotifyConst.java +++ b/extension/extension-notify-yunzhijia/src/main/java/org/dromara/dynamictp/extension/notify/yunzhijia/YunZhiJiaNotifyConst.java @@ -42,14 +42,25 @@ private YunZhiJiaNotifyConst() { public static final String PLATFORM_NAME = "YUNZHIJIA"; - public static final String ALARM_TEMPLATE = + public static final String ALARM_TEMPLATE_PREFIX = "【报警】 动态线程池告警 \n" + "服务名称:%s \n" + "实例信息:%s \n" + "环境:%s \n" + "线程池名称:%s \n" + "报警类型:%s \n" + - "报警阈值:%s \n" + + "报警阈值:%s \n"; + + public static final String ALARM_COMMON_TEMPLATE = "%s \n"; + public static final String ALARM_TEMPLATE_SUFFIX = + "上次报警时间:%s \n" + + "报警时间:%s \n" + + "接收人:@%s \n" + + "trace 信息:%s \n" + + "报警间隔:%ss \n" + + "扩展信息:%s \n"; + public static final String ALARM_TEMPLATE = + ALARM_TEMPLATE_PREFIX + "核心线程数:%s \n" + "最大线程数:%s \n" + "当前线程数:%s \n" + @@ -66,12 +77,7 @@ private YunZhiJiaNotifyConst() { "拒绝任务数量:%s \n" + "执行超时任务数量:%s \n" + "等待超时任务数量:%s \n" + - "上次报警时间:%s \n" + - "报警时间:%s \n" + - "接收人:@%s \n" + - "trace 信息:%s \n" + - "报警间隔:%ss \n" + - "扩展信息:%s \n"; + ALARM_TEMPLATE_SUFFIX; public static final String CHANGE_NOTICE_TEMPLATE = "【通知】 动态线程池参数变更 \n" + diff --git a/spring/src/main/java/org/dromara/dynamictp/spring/DtpPostProcessor.java b/spring/src/main/java/org/dromara/dynamictp/spring/DtpPostProcessor.java index 80e0cbef7..ed80321f4 100644 --- a/spring/src/main/java/org/dromara/dynamictp/spring/DtpPostProcessor.java +++ b/spring/src/main/java/org/dromara/dynamictp/spring/DtpPostProcessor.java @@ -57,7 +57,9 @@ import java.util.Set; import java.util.concurrent.Executor; import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; import java.util.concurrent.ScheduledThreadPoolExecutor; +import java.util.concurrent.ThreadFactory; import java.util.concurrent.ThreadPoolExecutor; import static org.dromara.dynamictp.core.support.DtpLifecycleSupport.shutdownGracefulAsync; @@ -198,7 +200,11 @@ private ScheduledThreadPoolExecutorProxy newScheduledTpProxy(String name, Schedu } private VirtualThreadExecutorProxy newVirtualThreadProxy(String name, ExecutorService originExecutor) { - return new VirtualThreadExecutorProxy(originExecutor); + ThreadFactory factory = Thread.ofVirtual().name(name).factory(); + ExecutorService executor = Executors.newThreadPerTaskExecutor(factory); + val proxy = new VirtualThreadExecutorProxy(executor); + shutdownGracefulAsync(originExecutor, name, 0); + return proxy; } private void tryWrapTaskDecorator(String poolName, ThreadPoolTaskExecutor poolTaskExecutor, ThreadPoolExecutorProxy proxy) throws IllegalAccessException { diff --git a/test/test-core/pom.xml b/test/test-core/pom.xml index 6ae1ac3b5..7dcdb18d8 100644 --- a/test/test-core/pom.xml +++ b/test/test-core/pom.xml @@ -20,5 +20,22 @@ spring-aspects test + + org.assertj + assertj-core + test + + + + + org.apache.maven.plugins + maven-compiler-plugin + + 21 + 21 + + + + diff --git a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/notify/AbstractDtpNotifierTest.java b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/notify/AbstractDtpNotifierTest.java index 31402d14c..e1b1fb5ac 100644 --- a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/notify/AbstractDtpNotifierTest.java +++ b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/notify/AbstractDtpNotifierTest.java @@ -117,6 +117,17 @@ public void testSendAlarmMsg() { Mockito.verify(this.notifier, Mockito.times(1)).send(any(), anyString()); } + @Test + public void testSendCommonAlarmMsg() { + AbstractDtpNotifier notifier = new DtpDingNotifier(this.notifier); + NotifyPlatform notifyPlatform = new NotifyPlatform(); + NotifyItemEnum notifyItemEnum = NotifyItemEnum.LIVENESS; + DtpNotifyCtxHolder.set(new AlarmCtx(ExecutorWrapper.of(dtpExecutor), new NotifyItem())); + notifier.sendCommonAlarmMsg(notifyPlatform, notifyItemEnum, "arg1", "arg2", "arg3"); + + Mockito.verify(this.notifier, Mockito.times(1)).send(any(), anyString()); + } + @Test public void testGetQueueName2() { Assert.assertEquals(dtpExecutor.getQueueType(), VARIABLE_LINKED_BLOCKING_QUEUE.getName()); diff --git a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/thread/ScheduledDtpExecutorTest.java b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/thread/ScheduledDtpExecutorTest.java index cb60abdba..fd9d2f946 100644 --- a/test/test-core/src/test/java/org/dromara/dynamictp/test/core/thread/ScheduledDtpExecutorTest.java +++ b/test/test-core/src/test/java/org/dromara/dynamictp/test/core/thread/ScheduledDtpExecutorTest.java @@ -29,6 +29,7 @@ import org.springframework.test.context.junit.jupiter.SpringExtension; import java.time.LocalDateTime; +import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; @PropertySource(value = "classpath:/dynamic-tp-nacos-demo-dtp-dev.yml", factory = YamlPropertySourceFactory.class) @@ -67,4 +68,14 @@ void testSubNotify() { dtpExecutor14.shutdownNow(); } + @Test + void testScheduleCancel() { + ScheduledDtpExecutor dtpExecutor12 = (ScheduledDtpExecutor) DtpRegistry.getExecutor("dtpExecutor12"); + ScheduledFuture scheduledFuture = dtpExecutor12.scheduleWithFixedDelay(() -> { + System.out.println(Thread.currentThread().getName() + "进来了," + + "当前时间是 "); + }, 0, 1000, TimeUnit.MILLISECONDS); + scheduledFuture.cancel(false); + } + }