Add new methods to get the last job instance/execution in JobInstance/JobExecution DAOs
Before this commit, getting the last job instance/execution required to load all job instances/executions from the database and filter them on the client side in memory. This commit introduces new methods that use database queries to get the last job instance/execution without the need to load all job instances/executions. This change improves memory consumption as well as the performance of starting the next instance of a job. Resolves BATCH-1784
This commit is contained in:
committed by
Michael Minella
parent
afc25dc873
commit
7c1fbede1b
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2018 the original author or authors.
|
||||
* Copyright 2006-2019 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.
|
||||
@@ -19,7 +19,6 @@ package org.springframework.batch.core;
|
||||
import java.util.Date;
|
||||
import java.util.HashMap;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Properties;
|
||||
|
||||
@@ -256,20 +255,19 @@ public class JobParametersBuilder {
|
||||
|
||||
String name = job.getName();
|
||||
JobParameters nextParameters;
|
||||
List<JobInstance> lastInstances = this.jobExplorer.getJobInstances(name, 0, 1);
|
||||
JobInstance lastInstance = this.jobExplorer.getLastJobInstance(name);
|
||||
JobParametersIncrementer incrementer = job.getJobParametersIncrementer();
|
||||
if (lastInstances.isEmpty()) {
|
||||
if (lastInstance == null) {
|
||||
// Start from a completely clean sheet
|
||||
nextParameters = incrementer.getNext(new JobParameters());
|
||||
}
|
||||
else {
|
||||
List<JobExecution> previousExecutions = this.jobExplorer.getJobExecutions(lastInstances.get(0));
|
||||
if (previousExecutions.isEmpty()) {
|
||||
JobExecution previousExecution = this.jobExplorer.getLastJobExecution(lastInstance);
|
||||
if (previousExecution == null) {
|
||||
// Normally this will not happen - an instance exists with no executions
|
||||
nextParameters = incrementer.getNext(new JobParameters());
|
||||
}
|
||||
else {
|
||||
JobExecution previousExecution = previousExecutions.get(0);
|
||||
nextParameters = incrementer.getNext(previousExecution.getJobParameters());
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2018 the original author or authors.
|
||||
* Copyright 2006-2019 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.
|
||||
@@ -49,6 +49,18 @@ public interface JobExplorer {
|
||||
*/
|
||||
List<JobInstance> getJobInstances(String jobName, int start, int count);
|
||||
|
||||
/**
|
||||
* Find the last job instance by Id for the given job.
|
||||
* @param jobName name of the job
|
||||
* @return the last job instance by Id if any or null otherwise
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
@Nullable
|
||||
default JobInstance getLastJobInstance(String jobName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve a {@link JobExecution} by its id. The complete object graph for
|
||||
* this execution should be returned (unless otherwise indicated) including
|
||||
@@ -95,6 +107,20 @@ public interface JobExplorer {
|
||||
*/
|
||||
List<JobExecution> getJobExecutions(JobInstance jobInstance);
|
||||
|
||||
/**
|
||||
* Find the last {@link JobExecution} that has been created for a given
|
||||
* {@link JobInstance}.
|
||||
* @param jobInstance the {@link JobInstance}
|
||||
* @return the last {@link JobExecution} that has been created for this instance or
|
||||
* {@code null} if no job execution is found for the given job instance.
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
@Nullable
|
||||
default JobExecution getLastJobExecution(JobInstance jobInstance) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve running job executions. The corresponding step executions may
|
||||
* not be fully hydrated (e.g. their execution context may be missing),
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2018 the original author or authors.
|
||||
* Copyright 2006-2019 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.
|
||||
@@ -90,6 +90,18 @@ public class SimpleJobExplorer implements JobExplorer {
|
||||
return executions;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.batch.core.explore.JobExplorer#getLastJobExecution(
|
||||
* org.springframework.batch.core.JobInstance)
|
||||
*/
|
||||
@Nullable
|
||||
public JobExecution getLastJobExecution(JobInstance jobInstance) {
|
||||
return jobExecutionDao.getLastJobExecution(jobInstance);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
@@ -163,6 +175,18 @@ public class SimpleJobExplorer implements JobExplorer {
|
||||
return jobInstanceDao.getJobInstance(instanceId);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see
|
||||
* org.springframework.batch.core.explore.JobExplorer#getLastJobInstance(java
|
||||
* .lang.String)
|
||||
*/
|
||||
@Override
|
||||
public JobInstance getLastJobInstance(String jobName) {
|
||||
return jobInstanceDao.getLastJobInstance(jobName);
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
||||
@@ -81,7 +81,10 @@ JobInstanceDao, InitializingBean {
|
||||
private static final String FIND_JOB_NAMES = "SELECT distinct JOB_NAME from %PREFIX%JOB_INSTANCE order by JOB_NAME";
|
||||
|
||||
private static final String FIND_LAST_JOBS_BY_NAME = "SELECT JOB_INSTANCE_ID, JOB_NAME from %PREFIX%JOB_INSTANCE where JOB_NAME = ? order by JOB_INSTANCE_ID desc";
|
||||
|
||||
|
||||
private static final String FIND_LAST_JOB_INSTANCE_BY_JOB_NAME = "SELECT JOB_INSTANCE_ID, JOB_NAME from %PREFIX%JOB_INSTANCE I1 where" +
|
||||
" I1.JOB_NAME = ? and I1.JOB_INSTANCE_ID in (SELECT max(I2.JOB_INSTANCE_ID) from %PREFIX%JOB_INSTANCE I2 where I2.JOB_NAME = ?)";
|
||||
|
||||
private static final String FIND_LAST_JOBS_LIKE_NAME = "SELECT JOB_INSTANCE_ID, JOB_NAME from %PREFIX%JOB_INSTANCE where JOB_NAME like ? order by JOB_INSTANCE_ID desc";
|
||||
|
||||
private DataFieldMaxValueIncrementer jobIncrementer;
|
||||
@@ -237,6 +240,25 @@ JobInstanceDao, InitializingBean {
|
||||
return result;
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
* @see org.springframework.batch.core.repository.dao.JobInstanceDao#
|
||||
* getLastJobInstance(java.lang.String)
|
||||
*/
|
||||
@Override
|
||||
@Nullable
|
||||
public JobInstance getLastJobInstance(String jobName) {
|
||||
try {
|
||||
return getJdbcTemplate().queryForObject(
|
||||
getQuery(FIND_LAST_JOB_INSTANCE_BY_JOB_NAME),
|
||||
new Object[] { jobName, jobName },
|
||||
new JobInstanceRowMapper());
|
||||
} catch (EmptyResultDataAccessException e) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* (non-Javadoc)
|
||||
*
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2018 the original author or authors.
|
||||
* Copyright 2006-2019 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.
|
||||
@@ -96,6 +96,18 @@ public interface JobInstanceDao {
|
||||
*/
|
||||
List<JobInstance> getJobInstances(String jobName, int start, int count);
|
||||
|
||||
/**
|
||||
* Fetch the last job instance by Id for the given job.
|
||||
* @param jobName name of the job
|
||||
* @return the last job instance by Id if any or null otherwise
|
||||
*
|
||||
* @since 4.2
|
||||
*/
|
||||
@Nullable
|
||||
default JobInstance getLastJobInstance(String jobName) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieve the names of all job instances sorted alphabetically - i.e. jobs
|
||||
* that have ever been executed.
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2018 the original author or authors.
|
||||
* Copyright 2006-2019 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.
|
||||
@@ -106,6 +106,13 @@ public class MapJobInstanceDao implements JobInstanceDao {
|
||||
return subset(result, start, count);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JobInstance getLastJobInstance(String jobName) {
|
||||
List<JobInstance> jobInstances = getJobInstances(jobName, 0, 1);
|
||||
return jobInstances.isEmpty() ? null : jobInstances.get(0);
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public JobInstance getJobInstance(JobExecution jobExecution) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2006-2013 the original author or authors.
|
||||
* Copyright 2006-2019 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.
|
||||
@@ -42,6 +42,7 @@ import org.springframework.batch.core.repository.dao.StepExecutionDao;
|
||||
* @author Dave Syer
|
||||
* @author Will Schipp
|
||||
* @author Michael Minella
|
||||
* @author Mahmoud Ben Hassine
|
||||
*
|
||||
*/
|
||||
public class SimpleJobExplorerTests {
|
||||
@@ -82,6 +83,13 @@ public class SimpleJobExplorerTests {
|
||||
jobExplorer.getJobExecution(123L);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLastJobExecution() {
|
||||
when(jobExecutionDao.getLastJobExecution(jobInstance)).thenReturn(jobExecution);
|
||||
JobExecution lastJobExecution = jobExplorer.getLastJobExecution(jobInstance);
|
||||
assertEquals(jobExecution, lastJobExecution);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testMissingGetJobExecution() throws Exception {
|
||||
when(jobExecutionDao.getJobExecution(123L)).thenReturn(null);
|
||||
@@ -156,6 +164,13 @@ public class SimpleJobExplorerTests {
|
||||
jobExplorer.getJobInstances("foo", 0, 1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetLastJobInstance() {
|
||||
when(jobInstanceDao.getLastJobInstance("foo")).thenReturn(jobInstance);
|
||||
JobInstance lastJobInstance = jobExplorer.getLastJobInstance("foo");
|
||||
assertEquals(jobInstance, lastJobInstance);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetJobNames() throws Exception {
|
||||
jobInstanceDao.getJobNames();
|
||||
|
||||
@@ -505,6 +505,16 @@ public class CommandLineJobRunnerTests {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobInstance getLastJobInstance(String jobName) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public JobExecution getLastJobExecution(JobInstance jobInstance) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<JobInstance> getJobInstances(String jobName, int start, int count) {
|
||||
if (jobInstances == null) {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2008-2013 the original author or authors.
|
||||
* Copyright 2008-2019 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.
|
||||
@@ -154,6 +154,33 @@ public abstract class AbstractJobInstanceDaoTests {
|
||||
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Test
|
||||
public void testGetLastInstance() throws Exception {
|
||||
testCreateAndRetrieve();
|
||||
|
||||
// unrelated job instance that should be ignored by the query
|
||||
dao.createJobInstance("anotherJob", new JobParameters());
|
||||
|
||||
// we need two instances of the same job to check ordering
|
||||
dao.createJobInstance(fooJob, new JobParameters());
|
||||
|
||||
List<JobInstance> jobInstances = dao.getJobInstances(fooJob, 0, 2);
|
||||
assertEquals(2, jobInstances.size());
|
||||
JobInstance lastJobInstance = dao.getLastJobInstance(fooJob);
|
||||
assertNotNull(lastJobInstance);
|
||||
assertEquals(fooJob, lastJobInstance.getJobName());
|
||||
assertEquals("Last instance should be first on the list",
|
||||
jobInstances.get(0), lastJobInstance);
|
||||
}
|
||||
|
||||
@Transactional
|
||||
@Test
|
||||
public void testGetLastInstanceWhenNoInstance() {
|
||||
JobInstance lastJobInstance = dao.getLastJobInstance("NonExistingJob");
|
||||
assertNull(lastJobInstance);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and retrieve a job instance.
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user