This is an automated email from the ASF dual-hosted git repository.
SbloodyS pushed a commit to branch dev
in repository https://gitbox.apache.org/repos/asf/dolphinscheduler.git
The following commit(s) were added to refs/heads/dev by this push:
new fa0fe2eab9 [Fix-18692][Master] Fix ignored dependent task check
interval (#18694)
fa0fe2eab9 is described below
commit fa0fe2eab93abc2032af9558f1a7ffb6548152c8
Author: huangsheng <[email protected]>
AuthorDate: Wed Oct 14 10:36:19 2026 +0800
[Fix-18692][Master] Fix ignored dependent task check interval (#18694)
---
.../plugin/dependent/DependentLogicTask.java | 57 ++++++-
.../engine/executor/LogicTaskExecutorTest.java | 145 ++++++++++++++++
.../plugin/dependent/DependentLogicTaskTest.java | 189 +++++++++++++++++++++
3 files changed, 386 insertions(+), 5 deletions(-)
diff --git
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/executor/plugin/dependent/DependentLogicTask.java
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/executor/plugin/dependent/DependentLogicTask.java
index 484c7ef360..5dae467643 100644
---
a/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/executor/plugin/dependent/DependentLogicTask.java
+++
b/dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/executor/plugin/dependent/DependentLogicTask.java
@@ -32,17 +32,29 @@ import
org.apache.dolphinscheduler.server.master.engine.executor.plugin.ITaskPar
import
org.apache.dolphinscheduler.server.master.engine.workflow.execution.IWorkflowExecution;
import
org.apache.dolphinscheduler.server.master.exception.MasterTaskExecuteException;
+import java.util.concurrent.TimeUnit;
+import java.util.function.LongSupplier;
+
import lombok.extern.slf4j.Slf4j;
import com.fasterxml.jackson.core.type.TypeReference;
+import com.google.common.annotations.VisibleForTesting;
@Slf4j
public class DependentLogicTask extends AbstractLogicTask<DependentParameters>
{
+ private static final int DEFAULT_CHECK_INTERVAL_SECONDS = 10;
+
private final TaskExecutionContext taskExecutionContext;
private final DependentTaskTracker dependentTaskTracker;
+ private final long checkIntervalNanos;
+
+ private final LongSupplier nanoTimeSupplier;
+
+ private Long lastCheckTimeNanos;
+
public DependentLogicTask(TaskExecutionContext taskExecutionContext,
ProjectDao projectDao,
WorkflowDefinitionDao workflowDefinitionDao,
@@ -51,8 +63,26 @@ public class DependentLogicTask extends
AbstractLogicTask<DependentParameters> {
WorkflowInstanceDao workflowInstanceDao,
IWorkflowExecution workflowExecution,
TaskInstanceContextDao taskInstanceContextDao) {
+ this(taskExecutionContext, projectDao, workflowDefinitionDao,
taskDefinitionDao, taskInstanceDao,
+ workflowInstanceDao, workflowExecution,
taskInstanceContextDao, System::nanoTime);
+ }
+
+ @VisibleForTesting
+ DependentLogicTask(TaskExecutionContext taskExecutionContext,
+ ProjectDao projectDao,
+ WorkflowDefinitionDao workflowDefinitionDao,
+ TaskDefinitionDao taskDefinitionDao,
+ TaskInstanceDao taskInstanceDao,
+ WorkflowInstanceDao workflowInstanceDao,
+ IWorkflowExecution workflowExecution,
+ TaskInstanceContextDao taskInstanceContextDao,
+ LongSupplier nanoTimeSupplier) {
super(taskExecutionContext);
this.taskExecutionContext = taskExecutionContext;
+ this.nanoTimeSupplier = nanoTimeSupplier;
+ final Integer checkInterval =
taskParameters.getDependence().getCheckInterval();
+ this.checkIntervalNanos = TimeUnit.SECONDS.toNanos(
+ checkInterval == null ? DEFAULT_CHECK_INTERVAL_SECONDS :
checkInterval);
this.dependentTaskTracker = new DependentTaskTracker(
taskExecutionContext,
taskParameters,
@@ -72,22 +102,39 @@ public class DependentLogicTask extends
AbstractLogicTask<DependentParameters> {
@Override
public TaskExecutionStatus getTaskExecutionState() {
- if (isRunning()) {
- taskExecutionStatus =
dependentTaskTracker.getDependentTaskStatus();
+ synchronized (this) {
+ if (!isRunning()) {
+ return taskExecutionStatus;
+ }
+ final long now = nanoTimeSupplier.getAsLong();
+ if (lastCheckTimeNanos != null && now - lastCheckTimeNanos <
checkIntervalNanos) {
+ return taskExecutionStatus;
+ }
+ lastCheckTimeNanos = now;
+ }
+ final TaskExecutionStatus dependentState =
dependentTaskTracker.getDependentTaskStatus();
+ synchronized (this) {
+ // A pause or kill may have completed while the dependency query
was running.
+ if (isRunning()) {
+ taskExecutionStatus = dependentState;
+ }
return taskExecutionStatus;
}
- return taskExecutionStatus;
}
@Override
public void pause() throws MasterTaskExecuteException {
- onTaskPaused();
+ synchronized (this) {
+ onTaskPaused();
+ }
log.info("Pause task : {} success",
taskExecutionContext.getTaskName());
}
@Override
public void kill() throws MasterTaskExecuteException {
- onTaskKilled();
+ synchronized (this) {
+ onTaskKilled();
+ }
log.info("Kill task : {} success", taskExecutionContext.getTaskName());
}
diff --git
a/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/engine/executor/LogicTaskExecutorTest.java
b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/engine/executor/LogicTaskExecutorTest.java
new file mode 100644
index 0000000000..131ca9ac44
--- /dev/null
+++
b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/engine/executor/LogicTaskExecutorTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.engine.executor;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import org.apache.dolphinscheduler.common.enums.Flag;
+import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext;
+import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus;
+import
org.apache.dolphinscheduler.plugin.task.api.parameters.AbstractParameters;
+import
org.apache.dolphinscheduler.server.master.engine.executor.plugin.ILogicTask;
+import
org.apache.dolphinscheduler.server.master.engine.executor.plugin.ILogicTaskPluginFactory;
+import
org.apache.dolphinscheduler.server.master.engine.executor.plugin.LogicTaskPluginFactoryBuilder;
+import
org.apache.dolphinscheduler.server.master.engine.executor.plugin.dependent.DependentLogicTask;
+import
org.apache.dolphinscheduler.server.master.engine.executor.plugin.dependent.DependentTaskTracker;
+import org.apache.dolphinscheduler.task.executor.TaskExecutorState;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeUnit;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.NullSource;
+import org.junit.jupiter.params.provider.ValueSource;
+import org.mockito.MockedConstruction;
+
+class LogicTaskExecutorTest {
+
+ private static final long FRAMEWORK_CHECK_INTERVAL_MILLIS =
TimeUnit.SECONDS.toMillis(10);
+
+ private MockedConstruction<DependentTaskTracker> dependentTaskTrackers;
+
+ @BeforeEach
+ void setUp() {
+ dependentTaskTrackers = mockConstruction(DependentTaskTracker.class,
+ (tracker, context) -> when(tracker.getDependentTaskStatus())
+ .thenReturn(TaskExecutionStatus.RUNNING_EXECUTION));
+ }
+
+ @AfterEach
+ void tearDown() {
+ dependentTaskTrackers.close();
+ }
+
+ @ParameterizedTest
+ @NullSource
+ @ValueSource(ints = {1, 5, 10, 20})
+ void frameworkUsesFixedCheckInterval(Integer checkInterval) throws
Exception {
+ LogicTaskExecutor taskExecutor =
createDependentTaskExecutor(checkInterval);
+
+ assertThat(taskExecutor.getRemainingTrackDelay()).isZero();
+ long beforeTrack = System.currentTimeMillis();
+
assertThat(taskExecutor.trackTaskExecutorState()).isEqualTo(TaskExecutorState.RUNNING);
+ long remainingDelay = taskExecutor.getRemainingTrackDelay();
+ long afterTrack = System.currentTimeMillis();
+
+ assertThat(remainingDelay).isBetween(
+ FRAMEWORK_CHECK_INTERVAL_MILLIS - (afterTrack - beforeTrack),
FRAMEWORK_CHECK_INTERVAL_MILLIS);
+
verify(dependentTaskTrackers.constructed().get(0)).getDependentTaskStatus();
+ }
+
+ @Test
+ void pauseIsReportedOnNextFrameworkCheck() throws Exception {
+ LogicTaskExecutor taskExecutor = createDependentTaskExecutor(20);
+ taskExecutor.trackTaskExecutorState();
+
+ taskExecutor.pause();
+
+ assertThat(taskExecutor.getRemainingTrackDelay()).isPositive()
+ .isLessThanOrEqualTo(FRAMEWORK_CHECK_INTERVAL_MILLIS);
+
assertThat(taskExecutor.trackTaskExecutorState()).isEqualTo(TaskExecutorState.PAUSED);
+ DependentTaskTracker tracker =
dependentTaskTrackers.constructed().get(0);
+ verify(tracker).getDependentTaskStatus();
+ verifyNoMoreInteractions(tracker);
+ }
+
+ @Test
+ void killIsReportedOnNextFrameworkCheck() throws Exception {
+ LogicTaskExecutor taskExecutor = createDependentTaskExecutor(20);
+ taskExecutor.trackTaskExecutorState();
+
+ taskExecutor.kill();
+
+ assertThat(taskExecutor.getRemainingTrackDelay()).isPositive()
+ .isLessThanOrEqualTo(FRAMEWORK_CHECK_INTERVAL_MILLIS);
+
assertThat(taskExecutor.trackTaskExecutorState()).isEqualTo(TaskExecutorState.KILLED);
+ DependentTaskTracker tracker =
dependentTaskTrackers.constructed().get(0);
+ verify(tracker).getDependentTaskStatus();
+ verifyNoMoreInteractions(tracker);
+ }
+
+ private LogicTaskExecutor createDependentTaskExecutor(Integer
checkInterval) throws Exception {
+ TaskExecutionContext taskExecutionContext = new TaskExecutionContext();
+ taskExecutionContext.setTaskType("DEPENDENT");
+ taskExecutionContext.setTaskName("dependent");
+ taskExecutionContext.setDryRun(Flag.NO.getCode());
+ taskExecutionContext.setTaskParams(checkInterval == null ?
"{\"dependence\":{}}"
+ : "{\"dependence\":{\"checkInterval\":" + checkInterval +
"}}");
+
+ return createTaskExecutor(taskExecutionContext, new DependentLogicTask(
+ taskExecutionContext, null, null, null, null, null, null,
null));
+ }
+
+ @SuppressWarnings("unchecked")
+ private LogicTaskExecutor createTaskExecutor(TaskExecutionContext
taskExecutionContext,
+ ILogicTask<? extends
AbstractParameters> logicTask) throws Exception {
+ ILogicTaskPluginFactory<? extends ILogicTask<? extends
AbstractParameters>> taskPluginFactory =
+ mock(ILogicTaskPluginFactory.class);
+
when(taskPluginFactory.getTaskType()).thenReturn(taskExecutionContext.getTaskType());
+ when(taskPluginFactory.createLogicTask(any())).thenAnswer(invocation
-> logicTask);
+ List<ILogicTaskPluginFactory<? extends ILogicTask<? extends
AbstractParameters>>> taskPluginFactories =
+ new ArrayList<>();
+ taskPluginFactories.add(taskPluginFactory);
+ LogicTaskExecutor taskExecutor = new
LogicTaskExecutor(LogicTaskExecutorBuilder.builder()
+ .taskExecutionContext(taskExecutionContext)
+ .logicTaskPluginFactoryBuilder(new
LogicTaskPluginFactoryBuilder(taskPluginFactories))
+ .build());
+ taskExecutor.start();
+ return taskExecutor;
+ }
+}
diff --git
a/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/engine/executor/plugin/dependent/DependentLogicTaskTest.java
b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/engine/executor/plugin/dependent/DependentLogicTaskTest.java
new file mode 100644
index 0000000000..46bcca16bf
--- /dev/null
+++
b/dolphinscheduler-master/src/test/java/org/apache/dolphinscheduler/server/master/engine/executor/plugin/dependent/DependentLogicTaskTest.java
@@ -0,0 +1,189 @@
+/*
+ * 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.engine.executor.plugin.dependent;
+
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.mockito.Mockito.mockConstruction;
+import static org.mockito.Mockito.times;
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.verifyNoMoreInteractions;
+import static org.mockito.Mockito.when;
+
+import org.apache.dolphinscheduler.plugin.task.api.TaskExecutionContext;
+import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus;
+
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
+import java.util.concurrent.Future;
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.CsvSource;
+import org.junit.jupiter.params.provider.EnumSource;
+import org.mockito.MockedConstruction;
+
+class DependentLogicTaskTest {
+
+ private static final int ASYNC_TEST_TIMEOUT_SECONDS = 5;
+
+ private final AtomicLong currentTimeNanos = new AtomicLong();
+
+ private MockedConstruction<DependentTaskTracker> dependentTaskTrackers;
+
+ @BeforeEach
+ void setUp() {
+ dependentTaskTrackers = mockConstruction(DependentTaskTracker.class,
+ (tracker, context) -> when(tracker.getDependentTaskStatus())
+ .thenReturn(TaskExecutionStatus.RUNNING_EXECUTION));
+ }
+
+ @AfterEach
+ void tearDown() {
+ dependentTaskTrackers.close();
+ }
+
+ @ParameterizedTest
+ @CsvSource(value = {"null, 10", "1, 1", "5, 5", "10, 10", "20, 20"},
nullValues = "null")
+ void dependencyQueriesUseConfiguredInterval(Integer checkInterval, long
expectedIntervalSeconds) {
+ DependentLogicTask logicTask = createDependentLogicTask(checkInterval);
+ DependentTaskTracker tracker =
dependentTaskTrackers.constructed().get(0);
+ when(tracker.getDependentTaskStatus())
+ .thenReturn(TaskExecutionStatus.RUNNING_EXECUTION,
TaskExecutionStatus.SUCCESS);
+
+
assertThat(logicTask.getTaskExecutionState()).isEqualTo(TaskExecutionStatus.RUNNING_EXECUTION);
+
assertThat(logicTask.getTaskExecutionState()).isEqualTo(TaskExecutionStatus.RUNNING_EXECUTION);
+
+ long expectedIntervalNanos =
TimeUnit.SECONDS.toNanos(expectedIntervalSeconds);
+ currentTimeNanos.set(expectedIntervalNanos - 1);
+
assertThat(logicTask.getTaskExecutionState()).isEqualTo(TaskExecutionStatus.RUNNING_EXECUTION);
+ verify(tracker).getDependentTaskStatus();
+
+ currentTimeNanos.set(expectedIntervalNanos);
+
assertThat(logicTask.getTaskExecutionState()).isEqualTo(TaskExecutionStatus.SUCCESS);
+ verify(tracker, times(2)).getDependentTaskStatus();
+ verifyNoMoreInteractions(tracker);
+ }
+
+ @ParameterizedTest
+ @CsvSource({"10, 2, 3", "15, 1, 2", "20, 1, 2"})
+ void frameworkChecksReturnCachedStateUntilQueryIsDue(int checkInterval,
int queriesAtTenSeconds,
+ int
queriesAtTwentySeconds) {
+ DependentLogicTask logicTask = createDependentLogicTask(checkInterval);
+ DependentTaskTracker tracker =
dependentTaskTrackers.constructed().get(0);
+
+
assertThat(logicTask.getTaskExecutionState()).isEqualTo(TaskExecutionStatus.RUNNING_EXECUTION);
+ verify(tracker).getDependentTaskStatus();
+
+ currentTimeNanos.set(TimeUnit.SECONDS.toNanos(10));
+
assertThat(logicTask.getTaskExecutionState()).isEqualTo(TaskExecutionStatus.RUNNING_EXECUTION);
+ verify(tracker, times(queriesAtTenSeconds)).getDependentTaskStatus();
+
+ currentTimeNanos.set(TimeUnit.SECONDS.toNanos(20));
+
assertThat(logicTask.getTaskExecutionState()).isEqualTo(TaskExecutionStatus.RUNNING_EXECUTION);
+ verify(tracker,
times(queriesAtTwentySeconds)).getDependentTaskStatus();
+ verifyNoMoreInteractions(tracker);
+ }
+
+ @ParameterizedTest
+ @EnumSource(value = TaskExecutionStatus.class, names = {"PAUSE", "KILL"})
+ void controlStateIsReturnedBeforeNextDependencyQuery(TaskExecutionStatus
controlState) throws Exception {
+ DependentLogicTask logicTask = createDependentLogicTask(20);
+ DependentTaskTracker tracker =
dependentTaskTrackers.constructed().get(0);
+
assertThat(logicTask.getTaskExecutionState()).isEqualTo(TaskExecutionStatus.RUNNING_EXECUTION);
+
+ currentTimeNanos.set(TimeUnit.SECONDS.toNanos(10));
+ controlTask(logicTask, controlState);
+ assertThat(logicTask.getTaskExecutionState()).isEqualTo(controlState);
+
+ currentTimeNanos.set(TimeUnit.SECONDS.toNanos(40));
+ assertThat(logicTask.getTaskExecutionState()).isEqualTo(controlState);
+ verify(tracker).getDependentTaskStatus();
+ verifyNoMoreInteractions(tracker);
+ }
+
+ @ParameterizedTest
+ @EnumSource(value = TaskExecutionStatus.class, names = {"SUCCESS",
"FAILURE"})
+ void finishedTaskDoesNotQueryDependenciesAgain(TaskExecutionStatus
finalState) {
+ DependentLogicTask logicTask = createDependentLogicTask(20);
+ DependentTaskTracker tracker =
dependentTaskTrackers.constructed().get(0);
+ when(tracker.getDependentTaskStatus()).thenReturn(finalState);
+
+ assertThat(logicTask.getTaskExecutionState()).isEqualTo(finalState);
+ currentTimeNanos.set(TimeUnit.SECONDS.toNanos(20));
+ assertThat(logicTask.getTaskExecutionState()).isEqualTo(finalState);
+ verify(tracker).getDependentTaskStatus();
+ verifyNoMoreInteractions(tracker);
+ }
+
+ @ParameterizedTest
+ @CsvSource({"PAUSE, RUNNING_EXECUTION", "PAUSE, SUCCESS", "PAUSE, FAILURE",
+ "KILL, RUNNING_EXECUTION", "KILL, SUCCESS", "KILL, FAILURE"})
+ void
dependentCheckDoesNotOverwriteConcurrentControlState(TaskExecutionStatus
expectedState,
+
TaskExecutionStatus dependentState) throws Exception {
+ DependentLogicTask logicTask = createDependentLogicTask(20);
+ DependentTaskTracker tracker =
dependentTaskTrackers.constructed().get(0);
+ CountDownLatch checkStarted = new CountDownLatch(1);
+ CountDownLatch finishCheck = new CountDownLatch(1);
+ when(tracker.getDependentTaskStatus()).thenAnswer(invocation -> {
+ checkStarted.countDown();
+ assertThat(finishCheck.await(ASYNC_TEST_TIMEOUT_SECONDS,
TimeUnit.SECONDS)).isTrue();
+ return dependentState;
+ });
+
+ ExecutorService stateTracker = Executors.newSingleThreadExecutor();
+ try {
+ Future<TaskExecutionStatus> trackedState =
stateTracker.submit(logicTask::getTaskExecutionState);
+ assertThat(checkStarted.await(ASYNC_TEST_TIMEOUT_SECONDS,
TimeUnit.SECONDS)).isTrue();
+
+ controlTask(logicTask, expectedState);
+
assertThat(logicTask.getTaskExecutionState()).isEqualTo(expectedState);
+ finishCheck.countDown();
+
+ assertThat(trackedState.get(ASYNC_TEST_TIMEOUT_SECONDS,
TimeUnit.SECONDS)).isEqualTo(expectedState);
+
assertThat(logicTask.getTaskExecutionState()).isEqualTo(expectedState);
+ verify(tracker).getDependentTaskStatus();
+ verifyNoMoreInteractions(tracker);
+ } finally {
+ finishCheck.countDown();
+ stateTracker.shutdownNow();
+
assertThat(stateTracker.awaitTermination(ASYNC_TEST_TIMEOUT_SECONDS,
TimeUnit.SECONDS)).isTrue();
+ }
+ }
+
+ private void controlTask(DependentLogicTask logicTask, TaskExecutionStatus
controlState) throws Exception {
+ if (controlState == TaskExecutionStatus.PAUSE) {
+ logicTask.pause();
+ } else {
+ logicTask.kill();
+ }
+ }
+
+ private DependentLogicTask createDependentLogicTask(Integer checkInterval)
{
+ TaskExecutionContext taskExecutionContext = new TaskExecutionContext();
+ taskExecutionContext.setTaskName("dependent");
+ taskExecutionContext.setTaskParams(checkInterval == null ?
"{\"dependence\":{}}"
+ : "{\"dependence\":{\"checkInterval\":" + checkInterval +
"}}");
+
+ return new DependentLogicTask(taskExecutionContext, null, null, null,
null, null, null, null,
+ currentTimeNanos::get);
+ }
+}