Skip to content

Commit decc1ee

Browse files
ThreeFire1ruanwenjun
authored andcommitted
[Fix-18707][Master] Protect other task lifecycle updates on persistence failure
1 parent 3061666 commit decc1ee

4 files changed

Lines changed: 684 additions & 39 deletions

File tree

‎dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/task/statemachine/AbstractTaskStateAction.java‎

Lines changed: 47 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949
import org.apache.commons.lang3.StringUtils;
5050

5151
import java.util.List;
52+
import java.util.function.Consumer;
5253

5354
import lombok.extern.slf4j.Slf4j;
5455

@@ -125,39 +126,43 @@ public void onFatalEvent(final IWorkflowExecution workflowExecution,
125126
private void persistentTaskInstanceFatalEventToDB(final ITaskExecution taskExecution,
126127
final TaskFatalLifecycleEvent taskFatalEvent) {
127128
final TaskInstance taskInstance = taskExecution.getTaskInstance();
128-
taskInstance.setState(TaskExecutionStatus.FAILURE);
129-
taskInstance.setEndTime(taskFatalEvent.getEndTime());
130-
taskInstanceDao.updateById(taskInstance);
129+
persistTaskInstanceUpdate(taskInstance, instance -> {
130+
instance.setState(TaskExecutionStatus.FAILURE);
131+
instance.setEndTime(taskFatalEvent.getEndTime());
132+
});
131133
}
132134

133135
@Override
134136
public void onDispatchedEvent(final IWorkflowExecution workflowExecution,
135137
final ITaskExecution taskExecution,
136138
final TaskDispatchedLifecycleEvent taskDispatchedEvent) {
137139
final TaskInstance taskInstance = taskExecution.getTaskInstance();
138-
taskInstance.setState(DISPATCH);
139-
taskInstance.setHost(taskDispatchedEvent.getExecutorHost());
140-
taskInstanceDao.updateById(taskInstance);
140+
persistTaskInstanceUpdate(taskInstance, instance -> {
141+
instance.setState(DISPATCH);
142+
instance.setHost(taskDispatchedEvent.getExecutorHost());
143+
});
141144
}
142145

143146
@Override
144147
public void onRuntimeContextChangedEvent(final IWorkflowExecution workflowExecution,
145148
final ITaskExecution taskExecution,
146149
final TaskRuntimeContextChangedEvent taskRuntimeContextChangedEvent) {
147150
final TaskInstance taskInstance = taskExecution.getTaskInstance();
148-
if (StringUtils.isNotEmpty(taskRuntimeContextChangedEvent.getRuntimeContext())) {
149-
taskInstance.setAppLink(taskRuntimeContextChangedEvent.getRuntimeContext());
150-
}
151-
taskInstanceDao.updateById(taskInstance);
151+
persistTaskInstanceUpdate(taskInstance, instance -> {
152+
if (StringUtils.isNotEmpty(taskRuntimeContextChangedEvent.getRuntimeContext())) {
153+
instance.setAppLink(taskRuntimeContextChangedEvent.getRuntimeContext());
154+
}
155+
});
152156
}
153157

154158
protected void persistentTaskInstanceStartedEventToDB(final ITaskExecution taskExecution,
155159
final TaskRunningLifecycleEvent taskRunningEvent) {
156160
final TaskInstance taskInstance = taskExecution.getTaskInstance();
157-
taskInstance.setState(TaskExecutionStatus.RUNNING_EXECUTION);
158-
taskInstance.setStartTime(taskRunningEvent.getStartTime());
159-
taskInstance.setLogPath(taskRunningEvent.getLogPath());
160-
taskInstanceDao.updateById(taskInstance);
161+
persistTaskInstanceUpdate(taskInstance, instance -> {
162+
instance.setState(TaskExecutionStatus.RUNNING_EXECUTION);
163+
instance.setStartTime(taskRunningEvent.getStartTime());
164+
instance.setLogPath(taskRunningEvent.getLogPath());
165+
});
161166
}
162167

163168
@Override
@@ -173,8 +178,7 @@ public void onPausedEvent(final IWorkflowExecution workflowExecution,
173178
private void persistentTaskInstancePausedEventToDB(final ITaskExecution taskExecution,
174179
final TaskPausedLifecycleEvent taskPausedEvent) {
175180
final TaskInstance taskInstance = taskExecution.getTaskInstance();
176-
taskInstance.setState(TaskExecutionStatus.PAUSE);
177-
taskInstanceDao.updateById(taskInstance);
181+
persistTaskInstanceUpdate(taskInstance, instance -> instance.setState(TaskExecutionStatus.PAUSE));
178182
}
179183

180184
@Override
@@ -190,9 +194,10 @@ public void onKilledEvent(final IWorkflowExecution workflowExecution,
190194
private void persistentTaskInstanceKilledEventToDB(final ITaskExecution taskExecution,
191195
final TaskKilledLifecycleEvent taskKilledEvent) {
192196
final TaskInstance taskInstance = taskExecution.getTaskInstance();
193-
taskInstance.setState(TaskExecutionStatus.KILL);
194-
taskInstance.setEndTime(taskKilledEvent.getEndTime());
195-
taskInstanceDao.updateById(taskInstance);
197+
persistTaskInstanceUpdate(taskInstance, instance -> {
198+
instance.setState(TaskExecutionStatus.KILL);
199+
instance.setEndTime(taskKilledEvent.getEndTime());
200+
});
196201

197202
}
198203

@@ -223,9 +228,10 @@ public void onFailedEvent(final IWorkflowExecution workflowExecution,
223228
private void persistentTaskInstanceFailedEventToDB(final ITaskExecution taskExecution,
224229
final TaskFailedLifecycleEvent taskFailedEvent) {
225230
final TaskInstance taskInstance = taskExecution.getTaskInstance();
226-
taskInstance.setState(TaskExecutionStatus.FAILURE);
227-
taskInstance.setEndTime(taskFailedEvent.getEndTime());
228-
taskInstanceDao.updateById(taskInstance);
231+
persistTaskInstanceUpdate(taskInstance, instance -> {
232+
instance.setState(TaskExecutionStatus.FAILURE);
233+
instance.setEndTime(taskFailedEvent.getEndTime());
234+
});
229235
}
230236

231237
@Override
@@ -247,24 +253,32 @@ protected void mergeTaskVarPoolToWorkflow(final IWorkflowExecution workflowExecu
247253
workflowInstance.setVarPool(VarPoolUtils.serializeVarPool(finalVarPool));
248254
}
249255

256+
/**
257+
* Persist an event's fields before applying them to the shared instance, so a failed update remains retryable.
258+
* The updater must only assign the event's fields and must be safe to apply to both instances. Compute merged
259+
* values before calling this method; do not publish events or mutate nested objects in the updater.
260+
*/
261+
protected void persistTaskInstanceUpdate(final TaskInstance taskInstance,
262+
final Consumer<TaskInstance> updater) {
263+
final TaskInstance taskInstanceToUpdate = new TaskInstance();
264+
BeanUtils.copyProperties(taskInstance, taskInstanceToUpdate);
265+
updater.accept(taskInstanceToUpdate);
266+
taskInstanceDao.updateById(taskInstanceToUpdate);
267+
updater.accept(taskInstance);
268+
}
269+
250270
protected void persistentTaskInstanceSuccessEventToDB(final ITaskExecution taskExecution,
251271
final TaskSuccessLifecycleEvent taskSuccessEvent) {
252272
final TaskInstance taskInstance = taskExecution.getTaskInstance();
253273
final List<Property> finalVarPool = VarPoolUtils.mergeVarPoolJsonString(taskInstance.getVarPool(),
254274
JSONUtils.toJsonString(taskSuccessEvent.getVarPool()));
255275
final String serializedFinalVarPool = VarPoolUtils.serializeVarPool(finalVarPool);
256276

257-
// Keep the shared state retryable if persisting the success result throws.
258-
final TaskInstance taskInstanceToUpdate = new TaskInstance();
259-
BeanUtils.copyProperties(taskInstance, taskInstanceToUpdate);
260-
taskInstanceToUpdate.setState(TaskExecutionStatus.SUCCESS);
261-
taskInstanceToUpdate.setEndTime(taskSuccessEvent.getEndTime());
262-
taskInstanceToUpdate.setVarPool(serializedFinalVarPool);
263-
taskInstanceDao.updateById(taskInstanceToUpdate);
264-
265-
taskInstance.setState(TaskExecutionStatus.SUCCESS);
266-
taskInstance.setEndTime(taskSuccessEvent.getEndTime());
267-
taskInstance.setVarPool(serializedFinalVarPool);
277+
persistTaskInstanceUpdate(taskInstance, instance -> {
278+
instance.setState(TaskExecutionStatus.SUCCESS);
279+
instance.setEndTime(taskSuccessEvent.getEndTime());
280+
instance.setVarPool(serializedFinalVarPool);
281+
});
268282
}
269283

270284
/**

‎dolphinscheduler-master/src/main/java/org/apache/dolphinscheduler/server/master/engine/task/statemachine/TaskSubmittedStateAction.java‎

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,6 @@
1919

2020
import org.apache.dolphinscheduler.common.utils.DateUtils;
2121
import org.apache.dolphinscheduler.dao.entity.TaskInstance;
22-
import org.apache.dolphinscheduler.dao.repository.TaskInstanceDao;
2322
import org.apache.dolphinscheduler.plugin.task.api.enums.TaskExecutionStatus;
2423
import org.apache.dolphinscheduler.server.master.engine.task.dispatcher.WorkerGroupDispatcherCoordinator;
2524
import org.apache.dolphinscheduler.server.master.engine.task.execution.ITaskExecution;
@@ -56,9 +55,6 @@ public class TaskSubmittedStateAction extends AbstractTaskStateAction {
5655
@Autowired
5756
private WorkerGroupDispatcherCoordinator workerGroupDispatcherCoordinator;
5857

59-
@Autowired
60-
private TaskInstanceDao taskInstanceDao;
61-
6258
@Override
6359
public void onStartEvent(final IWorkflowExecution workflowExecution,
6460
final ITaskExecution taskExecution,
@@ -104,8 +100,7 @@ public void onDispatchEvent(final IWorkflowExecution workflowExecution,
104100
taskInstance.getFirstSubmitTime(),
105101
taskInstance.getDelayTime() * 60L) * 1_000;
106102
if (remainTimeMills > 0) {
107-
taskInstance.setState(TaskExecutionStatus.DELAY_EXECUTION);
108-
taskInstanceDao.updateById(taskInstance);
103+
persistTaskInstanceUpdate(taskInstance, instance -> instance.setState(TaskExecutionStatus.DELAY_EXECUTION));
109104
log.info("Current taskInstance: {} is choose delay execution, delay time: {}/min, remainTime: {}/ms",
110105
taskInstance.getName(),
111106
taskInstance.getDelayTime(),

0 commit comments

Comments
 (0)