Improve step execution polling and retrieval

Resolves #3790
This commit is contained in:
Henning Poettker
2022-10-05 14:11:12 +02:00
committed by Mahmoud Ben Hassine
parent 708f1c8216
commit c68da18d3e
5 changed files with 71 additions and 33 deletions

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2019 the original author or authors. * Copyright 2013-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -26,6 +26,7 @@ import java.util.Properties;
import java.util.Set; import java.util.Set;
import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.Semaphore; import java.util.concurrent.Semaphore;
import java.util.stream.Collectors;
import javax.batch.operations.BatchRuntimeException; import javax.batch.operations.BatchRuntimeException;
import javax.batch.operations.JobExecutionAlreadyCompleteException; import javax.batch.operations.JobExecutionAlreadyCompleteException;
import javax.batch.operations.JobExecutionIsRunningException; import javax.batch.operations.JobExecutionIsRunningException;
@@ -47,6 +48,7 @@ import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.BatchStatus; import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.Entity;
import org.springframework.batch.core.ExitStatus; import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Job; import org.springframework.batch.core.Job;
import org.springframework.batch.core.JobParameters; import org.springframework.batch.core.JobParameters;
@@ -412,9 +414,11 @@ public class JsrJobOperator implements JobOperator, ApplicationContextAware, Ini
List<StepExecution> batchExecutions = new ArrayList<>(); List<StepExecution> batchExecutions = new ArrayList<>();
if(executions != null) { if(executions != null) {
for (org.springframework.batch.core.StepExecution stepExecution : executions) { Set<Long> stepExecutionIds = executions.stream().map(Entity::getId).collect(Collectors.toSet());
if(!stepExecution.getStepName().contains(":partition")) { org.springframework.batch.core.JobExecution jobExecution = jobExplorer.getJobExecution(executionId);
batchExecutions.add(new JsrStepExecution(jobExplorer.getStepExecution(executionId, stepExecution.getId()))); for (org.springframework.batch.core.StepExecution stepExecution : jobExecution.getStepExecutions()) {
if(!stepExecution.getStepName().contains(":partition") && stepExecutionIds.contains(stepExecution.getId())) {
batchExecutions.add(new JsrStepExecution(stepExecution));
} }
} }
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2006-2013 the original author or authors. * Copyright 2006-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -16,9 +16,12 @@
package org.springframework.batch.core.partition.support; package org.springframework.batch.core.partition.support;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.beans.factory.InitializingBean; import org.springframework.beans.factory.InitializingBean;
@@ -90,14 +93,16 @@ public class RemoteStepExecutionAggregator implements StepExecutionAggregator, I
if (executions == null) { if (executions == null) {
return; return;
} }
Collection<StepExecution> updates = new ArrayList<>(); Set<Long> stepExecutionIds = executions.stream().map(stepExecution -> {
for (StepExecution stepExecution : executions) {
Long id = stepExecution.getId(); Long id = stepExecution.getId();
Assert.state(id != null, "StepExecution has null id. It must be saved first: " + stepExecution); Assert.state(id != null, "StepExecution has null id. It must be saved first: " + stepExecution);
StepExecution update = jobExplorer.getStepExecution(stepExecution.getJobExecutionId(), id); return id;
Assert.state(update != null, "Could not reload StepExecution from JobRepository: " + stepExecution); }).collect(Collectors.toSet());
updates.add(update); JobExecution jobExecution = jobExplorer.getJobExecution(result.getJobExecutionId());
} Assert.state(jobExecution != null,
"Could not load JobExecution from JobRepository for id " + result.getJobExecutionId());
List<StepExecution> updates = jobExecution.getStepExecutions().stream()
.filter(stepExecution -> stepExecutionIds.contains(stepExecution.getId())).collect(Collectors.toList());
delegate.aggregate(result, updates); delegate.aggregate(result, updates);
} }

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright 2013-2018 the original author or authors. * Copyright 2013-2023 the original author or authors.
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
@@ -403,8 +403,6 @@ public class JsrJobOperatorTests extends AbstractJsrTestCase {
jobExecution.addStepExecutions(stepExecutions); jobExecution.addStepExecutions(stepExecutions);
when(jobExplorer.getJobExecution(5L)).thenReturn(jobExecution); when(jobExplorer.getJobExecution(5L)).thenReturn(jobExecution);
when(jobExplorer.getStepExecution(5L, 1L)).thenReturn(new StepExecution("step1", jobExecution, 1L));
when(jobExplorer.getStepExecution(5L, 2L)).thenReturn(new StepExecution("step2", jobExecution, 2L));
List<javax.batch.runtime.StepExecution> results = jsrJobOperator.getStepExecutions(5L); List<javax.batch.runtime.StepExecution> results = jsrJobOperator.getStepExecutions(5L);
@@ -429,8 +427,6 @@ public class JsrJobOperatorTests extends AbstractJsrTestCase {
jobExecution.addStepExecutions(stepExecutions); jobExecution.addStepExecutions(stepExecutions);
when(jobExplorer.getJobExecution(5L)).thenReturn(jobExecution); when(jobExplorer.getJobExecution(5L)).thenReturn(jobExecution);
when(jobExplorer.getStepExecution(5L, 1L)).thenReturn(new StepExecution("step1", jobExecution, 1L));
when(jobExplorer.getStepExecution(5L, 2L)).thenReturn(new StepExecution("step2", jobExecution, 2L));
List<javax.batch.runtime.StepExecution> results = jsrJobOperator.getStepExecutions(5L); List<javax.batch.runtime.StepExecution> results = jsrJobOperator.getStepExecutions(5L);

View File

@@ -1,19 +1,35 @@
/*
* Copyright 2009-2023 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.batch.integration.partition; package org.springframework.batch.integration.partition;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Iterator;
import java.util.List; import java.util.List;
import java.util.Set; import java.util.Set;
import java.util.concurrent.Callable; import java.util.concurrent.Callable;
import java.util.concurrent.Future; import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;
import javax.sql.DataSource; import javax.sql.DataSource;
import org.apache.commons.logging.Log; import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory; import org.apache.commons.logging.LogFactory;
import org.springframework.batch.core.JobExecution;
import org.springframework.batch.core.Step; import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution; import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.explore.JobExplorer; import org.springframework.batch.core.explore.JobExplorer;
@@ -242,19 +258,12 @@ public class MessageChannelPartitionHandler implements PartitionHandler, Initial
Callable<Collection<StepExecution>> callback = new Callable<Collection<StepExecution>>() { Callable<Collection<StepExecution>> callback = new Callable<Collection<StepExecution>>() {
@Override @Override
public Collection<StepExecution> call() throws Exception { public Collection<StepExecution> call() throws Exception {
Set<Long> currentStepExecutionIds = split.stream().map(StepExecution::getId).collect(Collectors.toSet());
for(Iterator<StepExecution> stepExecutionIterator = split.iterator(); stepExecutionIterator.hasNext(); ) { JobExecution jobExecution = jobExplorer.getJobExecution(masterStepExecution.getJobExecutionId());
StepExecution curStepExecution = stepExecutionIterator.next(); jobExecution.getStepExecutions().stream()
.filter(stepExecution -> currentStepExecutionIds.contains(stepExecution.getId()))
if(!result.contains(curStepExecution)) { .filter(stepExecution -> !result.contains(stepExecution))
StepExecution partitionStepExecution = .filter(stepExecution -> !stepExecution.getStatus().isRunning()).forEach(result::add);
jobExplorer.getStepExecution(masterStepExecution.getJobExecutionId(), curStepExecution.getId());
if(!partitionStepExecution.getStatus().isRunning()) {
result.add(partitionStepExecution);
}
}
}
if(logger.isDebugEnabled()) { if(logger.isDebugEnabled()) {
logger.debug(String.format("Currently waiting on %s partitions to finish", split.size())); logger.debug(String.format("Currently waiting on %s partitions to finish", split.size()));

View File

@@ -1,5 +1,22 @@
/*
* Copyright 2020-2023 the original author or authors.
*
* Licensed 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
*
* https://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.springframework.batch.integration.partition; package org.springframework.batch.integration.partition;
import java.util.Arrays;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
import java.util.HashSet; import java.util.HashSet;
@@ -154,7 +171,12 @@ public class MessageChannelPartitionHandlerTests {
stepExecutions.add(partition2); stepExecutions.add(partition2);
stepExecutions.add(partition3); stepExecutions.add(partition3);
when(stepExecutionSplitter.split(any(StepExecution.class), eq(1))).thenReturn(stepExecutions); when(stepExecutionSplitter.split(any(StepExecution.class), eq(1))).thenReturn(stepExecutions);
when(jobExplorer.getStepExecution(eq(5L), any(Long.class))).thenReturn(partition2, partition1, partition3, partition3, partition3, partition3, partition4); JobExecution runningJobExecution = new JobExecution(5L, new JobParameters());
runningJobExecution.addStepExecutions(Arrays.asList(partition2, partition1, partition3));
JobExecution completedJobExecution = new JobExecution(5L, new JobParameters());
completedJobExecution.addStepExecutions(Arrays.asList(partition2, partition1, partition4));
when(jobExplorer.getJobExecution(5L)).thenReturn(runningJobExecution, runningJobExecution, runningJobExecution,
completedJobExecution);
//set //set
messageChannelPartitionHandler.setMessagingOperations(operations); messageChannelPartitionHandler.setMessagingOperations(operations);
@@ -198,7 +220,9 @@ public class MessageChannelPartitionHandlerTests {
stepExecutions.add(partition2); stepExecutions.add(partition2);
stepExecutions.add(partition3); stepExecutions.add(partition3);
when(stepExecutionSplitter.split(any(StepExecution.class), eq(1))).thenReturn(stepExecutions); when(stepExecutionSplitter.split(any(StepExecution.class), eq(1))).thenReturn(stepExecutions);
when(jobExplorer.getStepExecution(eq(5L), any(Long.class))).thenReturn(partition2, partition1, partition3); JobExecution runningJobExecution = new JobExecution(5L, new JobParameters());
runningJobExecution.addStepExecutions(Arrays.asList(partition2, partition1, partition3));
when(jobExplorer.getJobExecution(5L)).thenReturn(runningJobExecution);
//set //set
messageChannelPartitionHandler.setMessagingOperations(operations); messageChannelPartitionHandler.setMessagingOperations(operations);