From c0013ccfb58930c5d54f8161ea3b926c636796b4 Mon Sep 17 00:00:00 2001 From: Sanjana Date: Mon, 9 Mar 2026 11:00:47 +0530 Subject: [PATCH 1/3] [Improvement-18039][Metrics] Add missing metrics to Master and Worker modules --- .../TaskTimeoutLifecycleEventHandler.java | 1 + .../statemachine/AbstractTaskStateAction.java | 9 ++- .../WorkflowExecutionRunnableFactory.java | 6 +- .../AbstractWorkflowStateAction.java | 3 + .../worker/metrics/WorkerServerMetrics.java | 76 +++++++++---------- 5 files changed, 52 insertions(+), 43 deletions(-) diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/task/lifecycle/handler/TaskTimeoutLifecycleEventHandler.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/task/lifecycle/handler/TaskTimeoutLifecycleEventHandler.java index 419225fa9250..2f9d4c53f05f 100644 --- a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/task/lifecycle/handler/TaskTimeoutLifecycleEventHandler.java +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/task/lifecycle/handler/TaskTimeoutLifecycleEventHandler.java @@ -54,6 +54,7 @@ public void handle(final ITaskStateAction taskStateAction, // The task instance is not active, means it is already finished. return; } + org.apache.dolphinscheduler.server.master.metrics.TaskMetrics.incTaskInstanceByState("timeout"); final String taskName = taskExecutionRunnable.getName(); final TaskTimeoutStrategy timeoutNotifyStrategy = taskTimeoutLifecycleEvent.getTimeoutStrategy(); if (timeoutNotifyStrategy == null) { diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/task/statemachine/AbstractTaskStateAction.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/task/statemachine/AbstractTaskStateAction.java index 88281145c67c..01bf676d142b 100644 --- a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/task/statemachine/AbstractTaskStateAction.java +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/task/statemachine/AbstractTaskStateAction.java @@ -46,6 +46,7 @@ import org.apache.dolphinscheduler.server.master.engine.task.runnable.ITaskExecutionRunnable; import org.apache.dolphinscheduler.server.master.engine.workflow.lifecycle.event.WorkflowTopologyLogicalTransitionWithTaskFinishLifecycleEvent; import org.apache.dolphinscheduler.server.master.engine.workflow.runnable.IWorkflowExecutionRunnable; +import org.apache.dolphinscheduler.server.master.metrics.TaskMetrics; import org.apache.commons.lang3.StringUtils; @@ -109,6 +110,7 @@ public void onFatalEvent(final IWorkflowExecutionRunnable workflowExecutionRunna if (taskExecutionRunnable.isTaskInstanceCanRetry()) { taskExecutionRunnable.getWorkflowEventBus().publish(TaskRetryLifecycleEvent.of(taskExecutionRunnable)); + TaskMetrics.incTaskInstanceByState("retry"); return; } @@ -131,6 +133,7 @@ private void persistentTaskInstanceFatalEventToDB(final ITaskExecutionRunnable t taskInstance.setState(TaskExecutionStatus.FAILURE); taskInstance.setEndTime(taskFatalEvent.getEndTime()); taskInstanceDao.updateById(taskInstance); + TaskMetrics.incTaskInstanceByState("fail"); } @Override @@ -141,6 +144,7 @@ public void onDispatchedEvent(final IWorkflowExecutionRunnable workflowExecution taskInstance.setState(DISPATCH); taskInstance.setHost(taskDispatchedEvent.getExecutorHost()); taskInstanceDao.updateById(taskInstance); + TaskMetrics.incTaskInstanceByState("dispatch"); } @Override @@ -196,7 +200,7 @@ private void persistentTaskInstanceKilledEventToDB(final ITaskExecutionRunnable taskInstance.setState(TaskExecutionStatus.KILL); taskInstance.setEndTime(taskKilledEvent.getEndTime()); taskInstanceDao.updateById(taskInstance); - + TaskMetrics.incTaskInstanceByState("kill"); } @Override @@ -208,6 +212,7 @@ public void onFailedEvent(final IWorkflowExecutionRunnable workflowExecutionRunn if (taskExecutionRunnable.isTaskInstanceCanRetry()) { taskExecutionRunnable.getWorkflowEventBus().publish(TaskRetryLifecycleEvent.of(taskExecutionRunnable)); + TaskMetrics.incTaskInstanceByState("retry"); return; } // If all successors are condition tasks, then the task will not be marked as failure. @@ -229,6 +234,7 @@ private void persistentTaskInstanceFailedEventToDB(final ITaskExecutionRunnable taskInstance.setState(TaskExecutionStatus.FAILURE); taskInstance.setEndTime(taskFailedEvent.getEndTime()); taskInstanceDao.updateById(taskInstance); + TaskMetrics.incTaskInstanceByState("fail"); } @Override @@ -259,6 +265,7 @@ protected void persistentTaskInstanceSuccessEventToDB(final ITaskExecutionRunnab JSONUtils.toJsonString(taskSuccessEvent.getVarPool())); taskInstance.setVarPool(VarPoolUtils.serializeVarPool(finalVarPool)); taskInstanceDao.updateById(taskInstance); + TaskMetrics.incTaskInstanceByState("success"); } /** diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/runnable/WorkflowExecutionRunnableFactory.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/runnable/WorkflowExecutionRunnableFactory.java index 2f5b5841283a..87a91b60d576 100644 --- a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/runnable/WorkflowExecutionRunnableFactory.java +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/runnable/WorkflowExecutionRunnableFactory.java @@ -52,8 +52,12 @@ public class WorkflowExecutionRunnableFactory { */ @Transactional public IWorkflowExecutionRunnable createWorkflowExecuteRunnable(Command command) { + long startTime = System.currentTimeMillis(); deleteCommandOrThrow(command); - return doCreateWorkflowExecutionRunnable(command); + IWorkflowExecutionRunnable workflowExecutionRunnable = doCreateWorkflowExecutionRunnable(command); + org.apache.dolphinscheduler.server.master.metrics.WorkflowInstanceMetrics + .recordWorkflowInstanceGenerateTime(System.currentTimeMillis() - startTime); + return workflowExecutionRunnable; } /** diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/AbstractWorkflowStateAction.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/AbstractWorkflowStateAction.java index 459abc8a64be..a813ac37046a 100644 --- a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/AbstractWorkflowStateAction.java +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/AbstractWorkflowStateAction.java @@ -172,6 +172,9 @@ protected void transformWorkflowInstanceState(final IWorkflowExecutionRunnable w workflowInstanceDao.updateById(workflowInstance); log.info("Success set WorkflowExecuteRunnable: {} state from: {} to {}", workflowInstance.getName(), originState.name(), targetState.name()); + WorkflowInstanceMetrics.incWorkflowInstanceByStateAndWorkflowDefinitionCode( + targetState.name(), + String.valueOf(workflowInstance.getWorkflowDefinitionCode())); } catch (Exception ex) { workflowInstance.setState(originState); throw ex; diff --git a/dolphinscheduler-worker/src/main/java/org/apache/dolphinscheduler/server/worker/metrics/WorkerServerMetrics.java b/dolphinscheduler-worker/src/main/java/org/apache/dolphinscheduler/server/worker/metrics/WorkerServerMetrics.java index e17db2f34663..61f07a90d2c7 100644 --- a/dolphinscheduler-worker/src/main/java/org/apache/dolphinscheduler/server/worker/metrics/WorkerServerMetrics.java +++ b/dolphinscheduler-worker/src/main/java/org/apache/dolphinscheduler/server/worker/metrics/WorkerServerMetrics.java @@ -30,47 +30,41 @@ @UtilityClass public class WorkerServerMetrics { - private final Counter workerOverloadCounter = - Counter.builder("ds.worker.overload.count") - .description("overloaded workers count") - .register(Metrics.globalRegistry); - - private final Counter workerFullSubmitQueueCounter = - Counter.builder("ds.worker.full.submit.queue.count") - .description("full worker submit queues count") - .register(Metrics.globalRegistry); - - private final Counter workerResourceDownloadSuccessCounter = - Counter.builder("ds.worker.resource.download.count") - .tag("status", "success") - .description("worker resource download success count") - .register(Metrics.globalRegistry); - - private final Counter workerResourceDownloadFailCounter = - Counter.builder("ds.worker.resource.download.count") - .tag("status", "fail") - .description("worker resource download failure count") - .register(Metrics.globalRegistry); - - private final Counter workerHeartBeatCounter = - Counter.builder("ds.worker.heartbeat.count") - .description("worker heartbeat count") - .register(Metrics.globalRegistry); - - private final Timer workerResourceDownloadDurationTimer = - Timer.builder("ds.worker.resource.download.duration") - .publishPercentiles(0.5, 0.75, 0.95, 0.99) - .publishPercentileHistogram() - .description("time cost of resource download on workers") - .register(Metrics.globalRegistry); - - private final DistributionSummary workerResourceDownloadSizeDistribution = - DistributionSummary.builder("ds.worker.resource.download.size") - .baseUnit("bytes") - .publishPercentiles(0.5, 0.75, 0.95, 0.99) - .publishPercentileHistogram() - .description("size of downloaded resource files on worker") - .register(Metrics.globalRegistry); + private final Counter workerOverloadCounter = Counter.builder("ds.worker.overload.count") + .description("overloaded workers count") + .register(Metrics.globalRegistry); + + private final Counter workerFullSubmitQueueCounter = Counter.builder("ds.worker.full.submit.queue.count") + .description("full worker submit queues count") + .register(Metrics.globalRegistry); + + private final Counter workerResourceDownloadSuccessCounter = Counter.builder("ds.worker.resource.download.count") + .tag("status", "success") + .description("worker resource download success count") + .register(Metrics.globalRegistry); + + private final Counter workerResourceDownloadFailCounter = Counter.builder("ds.worker.resource.download.count") + .tag("status", "fail") + .description("worker resource download failure count") + .register(Metrics.globalRegistry); + + private final Counter workerHeartBeatCounter = Counter.builder("ds.worker.heartbeat.count") + .description("worker heartbeat count") + .register(Metrics.globalRegistry); + + private final Timer workerResourceDownloadDurationTimer = Timer.builder("ds.worker.resource.download.duration") + .publishPercentiles(0.5, 0.75, 0.95, 0.99) + .publishPercentileHistogram() + .description("time cost of resource download on workers") + .register(Metrics.globalRegistry); + + private final DistributionSummary workerResourceDownloadSizeDistribution = DistributionSummary + .builder("ds.worker.resource.download.size") + .baseUnit("bytes") + .publishPercentiles(0.5, 0.75, 0.95, 0.99) + .publishPercentileHistogram() + .description("size of downloaded resource files on worker") + .register(Metrics.globalRegistry); public void incWorkerOverloadCount() { workerOverloadCounter.increment(); From edeef4e390d29387cb2c0da41868bba7f6522686 Mon Sep 17 00:00:00 2001 From: Sanjana Date: Tue, 10 Mar 2026 23:08:05 +0530 Subject: [PATCH 2/3] [Improvement-18039][Metrics] Fix missing metrics imports and workflow state mapping --- .../AbstractWorkflowStateAction.java | 3 +- .../server/master/metrics/TaskMetrics.java | 27 ---------------- .../metrics/WorkflowInstanceMetrics.java | 32 +++++++++++++++---- 3 files changed, 27 insertions(+), 35 deletions(-) diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/AbstractWorkflowStateAction.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/AbstractWorkflowStateAction.java index a813ac37046a..abaae08ac383 100644 --- a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/AbstractWorkflowStateAction.java +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/statemachine/AbstractWorkflowStateAction.java @@ -36,6 +36,7 @@ import org.apache.dolphinscheduler.server.master.engine.workflow.lifecycle.event.WorkflowTopologyLogicalTransitionWithTaskFinishLifecycleEvent; import org.apache.dolphinscheduler.server.master.engine.workflow.policy.IWorkflowFailureStrategy; import org.apache.dolphinscheduler.server.master.engine.workflow.runnable.IWorkflowExecutionRunnable; +import org.apache.dolphinscheduler.server.master.metrics.WorkflowInstanceMetrics; import org.apache.dolphinscheduler.server.master.utils.WorkflowInstanceUtils; import org.apache.dolphinscheduler.service.alert.WorkflowAlertManager; @@ -173,7 +174,7 @@ protected void transformWorkflowInstanceState(final IWorkflowExecutionRunnable w log.info("Success set WorkflowExecuteRunnable: {} state from: {} to {}", workflowInstance.getName(), originState.name(), targetState.name()); WorkflowInstanceMetrics.incWorkflowInstanceByStateAndWorkflowDefinitionCode( - targetState.name(), + targetState, String.valueOf(workflowInstance.getWorkflowDefinitionCode())); } catch (Exception ex) { workflowInstance.setState(originState); diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/metrics/TaskMetrics.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/metrics/TaskMetrics.java index 8ea9f13c4dae..05b53aa7a3eb 100644 --- a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/metrics/TaskMetrics.java +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/metrics/TaskMetrics.java @@ -50,39 +50,12 @@ public class TaskMetrics { } - private final Counter taskDispatchCounter = - Counter.builder("ds.task.dispatch.count") - .description("Task dispatch count") - .register(Metrics.globalRegistry); - - private final Counter taskDispatchFailCounter = - Counter.builder("ds.task.dispatch.failure.count") - .description("Task dispatch failures count, retried ones included") - .register(Metrics.globalRegistry); - - private final Counter taskDispatchErrorCounter = - Counter.builder("ds.task.dispatch.error.count") - .description("Number of errors during task dispatch") - .register(Metrics.globalRegistry); - public synchronized void registerTaskPrepared(Supplier consumer) { Gauge.builder("ds.task.prepared", consumer) .description("Task prepared count") .register(Metrics.globalRegistry); } - public void incTaskDispatchFailed(int failedCount) { - taskDispatchFailCounter.increment(failedCount); - } - - public void incTaskDispatchError() { - taskDispatchErrorCounter.increment(); - } - - public void incTaskDispatch() { - taskDispatchCounter.increment(); - } - public void incTaskInstanceByState(final String state) { if (taskInstanceCounters.get(state) == null) { return; diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/metrics/WorkflowInstanceMetrics.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/metrics/WorkflowInstanceMetrics.java index 013c517bde87..f3a6d7dc4a1e 100644 --- a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/metrics/WorkflowInstanceMetrics.java +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/metrics/WorkflowInstanceMetrics.java @@ -17,6 +17,8 @@ package org.apache.dolphinscheduler.server.master.metrics; +import org.apache.dolphinscheduler.common.enums.WorkflowExecutionStatus; + import java.util.Set; import java.util.concurrent.TimeUnit; import java.util.function.Supplier; @@ -36,7 +38,7 @@ public class WorkflowInstanceMetrics { private final Set workflowInstanceStates = ImmutableSet.of( - "submit", "timeout", "finish", "failover", "success", "fail", "stop"); + "submit", "timeout", "finish", "failover", "success", "fail", "stop", "pause"); static { for (final String state : workflowInstanceStates) { @@ -78,18 +80,34 @@ public synchronized void registerWorkflowInstanceResubmitGauge(Supplier .register(Metrics.globalRegistry); } - public void incWorkflowInstanceByStateAndWorkflowDefinitionCode(final String state, - final String workflowDefinitionCode) { - // When tags need to be determined from local context, - // you have no choice but to construct or lookup the Meter inside your method body. - // The lookup cost is just a single hash lookup, so it is acceptable for most use cases. + public void incWorkflowInstanceByStateAndWorkflowDefinitionCode(WorkflowExecutionStatus state, + String workflowDefinitionCode) { Metrics.globalRegistry.counter( "ds.workflow.instance.count", - "state", state, + "state", getMetricState(state), "workflow.definition.code", workflowDefinitionCode) .increment(); } + private String getMetricState(WorkflowExecutionStatus state) { + switch (state) { + case SUBMITTED_SUCCESS: + return "submit"; + case FAILURE: + return "fail"; + case SUCCESS: + return "success"; + case STOP: + return "stop"; + case PAUSE: + return "pause"; + case FAILOVER: + return "failover"; + default: + return state.name().toLowerCase(); + } + } + public void cleanUpWorkflowInstanceCountMetricsByDefinitionCode(final Long workflowDefinitionCode) { for (final String state : workflowInstanceStates) { final Counter counter = Metrics.globalRegistry.counter( From cf0e05f4756afbeea8fd8e3a4ba6c8be88d145ba Mon Sep 17 00:00:00 2001 From: sanjana2505006 Date: Thu, 12 Mar 2026 00:10:04 +0530 Subject: [PATCH 3/3] Add unit tests for TaskMetrics and WorkflowInstanceMetrics to fix SonarQube coverage gate, and fix import style in WorkflowExecutionRunnableFactory --- .../WorkflowExecutionRunnableFactory.java | 4 +- .../master/metrics/TaskMetricsTest.java | 84 +++++++++ .../metrics/WorkflowInstanceMetricsTest.java | 175 ++++++++++++++++++ 3 files changed, 261 insertions(+), 2 deletions(-) create mode 100644 dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/metrics/TaskMetricsTest.java create mode 100644 dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/metrics/WorkflowInstanceMetricsTest.java diff --git a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/runnable/WorkflowExecutionRunnableFactory.java b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/runnable/WorkflowExecutionRunnableFactory.java index 87a91b60d576..b5bc3aeab45d 100644 --- a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/runnable/WorkflowExecutionRunnableFactory.java +++ b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/workflow/runnable/WorkflowExecutionRunnableFactory.java @@ -23,6 +23,7 @@ import org.apache.dolphinscheduler.dao.repository.WorkflowInstanceDao; import org.apache.dolphinscheduler.server.master.engine.command.ICommandHandler; import org.apache.dolphinscheduler.server.master.engine.exceptions.CommandDuplicateHandleException; +import org.apache.dolphinscheduler.server.master.metrics.WorkflowInstanceMetrics; import java.util.List; @@ -55,8 +56,7 @@ public IWorkflowExecutionRunnable createWorkflowExecuteRunnable(Command command) long startTime = System.currentTimeMillis(); deleteCommandOrThrow(command); IWorkflowExecutionRunnable workflowExecutionRunnable = doCreateWorkflowExecutionRunnable(command); - org.apache.dolphinscheduler.server.master.metrics.WorkflowInstanceMetrics - .recordWorkflowInstanceGenerateTime(System.currentTimeMillis() - startTime); + WorkflowInstanceMetrics.recordWorkflowInstanceGenerateTime(System.currentTimeMillis() - startTime); return workflowExecutionRunnable; } diff --git a/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/metrics/TaskMetricsTest.java b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/metrics/TaskMetricsTest.java new file mode 100644 index 000000000000..ea3d3bf3972d --- /dev/null +++ b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/metrics/TaskMetricsTest.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.server.master.metrics; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertTrue; + +import java.util.Arrays; +import java.util.List; + +import org.junit.jupiter.api.Test; + +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.Metrics; + +class TaskMetricsTest { + + @Test + void testIncTaskInstanceByState_validStates() { + List validStates = Arrays.asList( + "submit", "timeout", "finish", "failover", "retry", "dispatch", "success", "kill", "fail", "stop"); + + for (String state : validStates) { + Counter counter = Metrics.globalRegistry.find("ds.task.instance.count") + .tag("state", state) + .counter(); + assertNotNull(counter, "Counter should exist for state: " + state); + double before = counter.count(); + TaskMetrics.incTaskInstanceByState(state); + assertEquals(before + 1, counter.count(), 0.001, + "Counter should be incremented for state: " + state); + } + } + + @Test + void testIncTaskInstanceByState_invalidState() { + TaskMetrics.incTaskInstanceByState("nonexistent_state"); + Counter counter = Metrics.globalRegistry.find("ds.task.instance.count") + .tag("state", "nonexistent_state") + .counter(); + assertTrue(counter == null || counter.count() == 0, + "Counter should not exist or be zero for invalid state"); + } + + @Test + void testIncTaskInstanceByState_multipleIncrements() { + Counter counter = Metrics.globalRegistry.find("ds.task.instance.count") + .tag("state", "submit") + .counter(); + assertNotNull(counter); + double before = counter.count(); + + TaskMetrics.incTaskInstanceByState("submit"); + TaskMetrics.incTaskInstanceByState("submit"); + TaskMetrics.incTaskInstanceByState("submit"); + + assertEquals(before + 3, counter.count(), 0.001, + "Counter should be incremented by 3 after three calls"); + } + + @Test + void testRegisterTaskPrepared() { + TaskMetrics.registerTaskPrepared(() -> 5); + assertNotNull(Metrics.globalRegistry.find("ds.task.prepared").gauge(), + "Task prepared gauge should be registered"); + } + +} diff --git a/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/metrics/WorkflowInstanceMetricsTest.java b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/metrics/WorkflowInstanceMetricsTest.java new file mode 100644 index 000000000000..a45f2715931b --- /dev/null +++ b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/metrics/WorkflowInstanceMetricsTest.java @@ -0,0 +1,175 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.dolphinscheduler.server.master.metrics; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotNull; +import static org.junit.jupiter.api.Assertions.assertNull; + +import org.apache.dolphinscheduler.common.enums.WorkflowExecutionStatus; + +import org.junit.jupiter.api.Test; + +import io.micrometer.core.instrument.Counter; +import io.micrometer.core.instrument.Metrics; +import io.micrometer.core.instrument.Timer; + +class WorkflowInstanceMetricsTest { + + @Test + void testIncWorkflowInstanceByStateAndWorkflowDefinitionCode_submitState() { + String defCode = "test_submit_1"; + WorkflowInstanceMetrics.incWorkflowInstanceByStateAndWorkflowDefinitionCode( + WorkflowExecutionStatus.SUBMITTED_SUCCESS, defCode); + Counter counter = Metrics.globalRegistry.find("ds.workflow.instance.count") + .tag("state", "submit") + .tag("workflow.definition.code", defCode) + .counter(); + assertNotNull(counter, "Counter should be registered for submit state"); + assertEquals(1, counter.count(), 0.001); + } + + @Test + void testIncWorkflowInstanceByStateAndWorkflowDefinitionCode_failureState() { + String defCode = "test_failure_1"; + WorkflowInstanceMetrics.incWorkflowInstanceByStateAndWorkflowDefinitionCode( + WorkflowExecutionStatus.FAILURE, defCode); + Counter counter = Metrics.globalRegistry.find("ds.workflow.instance.count") + .tag("state", "fail") + .tag("workflow.definition.code", defCode) + .counter(); + assertNotNull(counter, "Counter should be registered for fail state"); + assertEquals(1, counter.count(), 0.001); + } + + @Test + void testIncWorkflowInstanceByStateAndWorkflowDefinitionCode_successState() { + String defCode = "test_success_1"; + WorkflowInstanceMetrics.incWorkflowInstanceByStateAndWorkflowDefinitionCode( + WorkflowExecutionStatus.SUCCESS, defCode); + Counter counter = Metrics.globalRegistry.find("ds.workflow.instance.count") + .tag("state", "success") + .tag("workflow.definition.code", defCode) + .counter(); + assertNotNull(counter, "Counter should be registered for success state"); + assertEquals(1, counter.count(), 0.001); + } + + @Test + void testIncWorkflowInstanceByStateAndWorkflowDefinitionCode_stopState() { + String defCode = "test_stop_1"; + WorkflowInstanceMetrics.incWorkflowInstanceByStateAndWorkflowDefinitionCode( + WorkflowExecutionStatus.STOP, defCode); + Counter counter = Metrics.globalRegistry.find("ds.workflow.instance.count") + .tag("state", "stop") + .tag("workflow.definition.code", defCode) + .counter(); + assertNotNull(counter, "Counter should be registered for stop state"); + assertEquals(1, counter.count(), 0.001); + } + + @Test + void testIncWorkflowInstanceByStateAndWorkflowDefinitionCode_pauseState() { + String defCode = "test_pause_1"; + WorkflowInstanceMetrics.incWorkflowInstanceByStateAndWorkflowDefinitionCode( + WorkflowExecutionStatus.PAUSE, defCode); + Counter counter = Metrics.globalRegistry.find("ds.workflow.instance.count") + .tag("state", "pause") + .tag("workflow.definition.code", defCode) + .counter(); + assertNotNull(counter, "Counter should be registered for pause state"); + assertEquals(1, counter.count(), 0.001); + } + + @Test + void testIncWorkflowInstanceByStateAndWorkflowDefinitionCode_failoverState() { + String defCode = "test_failover_1"; + WorkflowInstanceMetrics.incWorkflowInstanceByStateAndWorkflowDefinitionCode( + WorkflowExecutionStatus.FAILOVER, defCode); + Counter counter = Metrics.globalRegistry.find("ds.workflow.instance.count") + .tag("state", "failover") + .tag("workflow.definition.code", defCode) + .counter(); + assertNotNull(counter, "Counter should be registered for failover state"); + assertEquals(1, counter.count(), 0.001); + } + + @Test + void testIncWorkflowInstanceByStateAndWorkflowDefinitionCode_defaultMapping() { + String defCode = "test_running_1"; + WorkflowInstanceMetrics.incWorkflowInstanceByStateAndWorkflowDefinitionCode( + WorkflowExecutionStatus.RUNNING_EXECUTION, defCode); + Counter counter = Metrics.globalRegistry.find("ds.workflow.instance.count") + .tag("state", "running_execution") + .tag("workflow.definition.code", defCode) + .counter(); + assertNotNull(counter, "Counter should be registered for default-mapped state"); + assertEquals(1, counter.count(), 0.001); + } + + @Test + void testRecordCommandQueryTime() { + WorkflowInstanceMetrics.recordCommandQueryTime(100L); + Timer timer = Metrics.globalRegistry.find("ds.workflow.command.query.duration").timer(); + assertNotNull(timer, "Command query timer should be registered"); + assertEquals(1, timer.count(), "Timer should have recorded one event"); + } + + @Test + void testRecordWorkflowInstanceGenerateTime() { + WorkflowInstanceMetrics.recordWorkflowInstanceGenerateTime(200L); + Timer timer = Metrics.globalRegistry.find("ds.workflow.instance.generate.duration").timer(); + assertNotNull(timer, "Workflow instance generate timer should be registered"); + assertEquals(1, timer.count(), "Timer should have recorded one event"); + } + + @Test + void testRegisterWorkflowInstanceRunningGauge() { + WorkflowInstanceMetrics.registerWorkflowInstanceRunningGauge(() -> 10); + assertNotNull(Metrics.globalRegistry.find("ds.workflow.instance.running").gauge(), + "Running gauge should be registered"); + } + + @Test + void testRegisterWorkflowInstanceResubmitGauge() { + WorkflowInstanceMetrics.registerWorkflowInstanceResubmitGauge(() -> 3); + assertNotNull(Metrics.globalRegistry.find("ds.workflow.instance.resubmit").gauge(), + "Resubmit gauge should be registered"); + } + + @Test + void testCleanUpWorkflowInstanceCountMetricsByDefinitionCode() { + String defCode = "99999"; + WorkflowInstanceMetrics.incWorkflowInstanceByStateAndWorkflowDefinitionCode( + WorkflowExecutionStatus.SUCCESS, defCode); + Counter counterBefore = Metrics.globalRegistry.find("ds.workflow.instance.count") + .tag("state", "success") + .tag("workflow.definition.code", defCode) + .counter(); + assertNotNull(counterBefore, "Counter should exist before cleanup"); + + WorkflowInstanceMetrics.cleanUpWorkflowInstanceCountMetricsByDefinitionCode(99999L); + + Counter counterAfter = Metrics.globalRegistry.find("ds.workflow.instance.count") + .tag("state", "success") + .tag("workflow.definition.code", defCode) + .counter(); + assertNull(counterAfter, "Counter should be removed after cleanup"); + } + +}