Code review comment: If the job is cancelled by user, the `clearJob()` will be called twice. Set thess strings to empty,to ensure the idempotency of the `clearJob` function.

Code before review:
private void clearJob() {
Preconditions.checkState(state == JobState.FINISHED || state == JobState.CANCELLED);
LOG.debug("kill etl job and delete etl files. id: {}, state: {}", id, state);
SparkEtlJobHandler handler = new SparkEtlJobHandler();
if (state == JobState.CANCELLED) {
if ((!Strings.isNullOrEmpty(appId) && sparkResource.isYarnMaster()) || sparkLoadAppHandle != null) {
try {
handler.killEtlJob(sparkLoadAppHandle, appId, id, sparkResource);
} catch (Exception e) {
LOG.warn("kill etl job failed. id: {}, state: {}", id, state, e);
}
}
}
if (!Strings.isNullOrEmpty(etlOutputPath)) {
try {
String outputPath = etlOutputPath.substring(0, etlOutputPath.lastIndexOf("/"));
handler.deleteEtlOutputPath(outputPath, brokerDesc);
} catch (Exception e) {
LOG.warn("delete etl files failed. id: {}, state: {}", id, state, e);
}
}
LOG.debug("clear push tasks and infos that not persist. id: {}, state: {}", id, state);
writeLock();
try {
for (Map<Long, PushTask> sentReplicaPushTask : tabletToSentReplicaPushTask.values()) {
for (PushTask pushTask : sentReplicaPushTask.values()) {
if (pushTask == null) {
continue;
}
AgentTaskQueue.removeTask(pushTask.getBackendId(), pushTask.getTaskType(), pushTask.getSignature());
}
}
sparkLoadAppHandle = null;
resourceDesc = null;
etlOutputPath = "";
appId = "";
tableToLoadPartitions.clear();
indexToPushBrokerReaderParams.clear();
indexToSchemaHash.clear();
tabletToSentReplicaPushTask.clear();
finishedReplicas.clear();
quorumTablets.clear();
fullTablets.clear();
} finally {
writeUnlock();
}
}

Line under review: appId = "";

Code after addressing the review:
private void clearJob() {
Preconditions.checkState(state == JobState.FINISHED || state == JobState.CANCELLED);
LOG.debug("kill etl job and delete etl files. id: {}, state: {}", id, state);
SparkEtlJobHandler handler = new SparkEtlJobHandler();
if (state == JobState.CANCELLED) {
if ((!Strings.isNullOrEmpty(appId) && sparkResource.isYarnMaster()) || sparkLoadAppHandle != null) {
try {
handler.killEtlJob(sparkLoadAppHandle, appId, id, sparkResource);
} catch (Exception e) {
LOG.warn("kill etl job failed. id: {}, state: {}", id, state, e);
}
}
}
if (!Strings.isNullOrEmpty(etlOutputPath)) {
try {
String outputPath = etlOutputPath.substring(0, etlOutputPath.lastIndexOf("/"));
handler.deleteEtlOutputPath(outputPath, brokerDesc);
} catch (Exception e) {
LOG.warn("delete etl files failed. id: {}, state: {}", id, state, e);
}
}
LOG.debug("clear push tasks and infos that not persist. id: {}, state: {}", id, state);
writeLock();
try {
for (Map<Long, PushTask> sentReplicaPushTask : tabletToSentReplicaPushTask.values()) {
for (PushTask pushTask : sentReplicaPushTask.values()) {
if (pushTask == null) {
continue;
}
AgentTaskQueue.removeTask(pushTask.getBackendId(), pushTask.getTaskType(), pushTask.getSignature());
}
}
sparkLoadAppHandle = null;
resourceDesc = null;
etlOutputPath = "";
appId = "";
tableToLoadPartitions.clear();
indexToPushBrokerReaderParams.clear();
indexToSchemaHash.clear();
tabletToSentReplicaPushTask.clear();
finishedReplicas.clear();
quorumTablets.clear();
fullTablets.clear();
} finally {
writeUnlock();
}
}