JobParameters cannot be found in spring batch - spring

I need your help plizz!!
i have a spring batch app and i need to pass job parameters to my quartz job.
Here is my JobLauncher in which i want to pass each line of list as job parameters :
#Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
try {
JdbcTemplate Jd = new JdbcTemplate(ds);
List<QuartzParameters> list=null;
list=Jd.query("select * from FLUX_INFO",new QuartzParametersMapper());
for (QuartzParameters i : list) {
Job job = jobLocator.getJob(jobName);
JobParametersBuilder JP = new JobParametersBuilder();
JP.addString("PAYS", i.getPAYS());
JP.addString("CRON", i.getCRON());
JP.addString("CLASSAPP",i.getCLASSAPP());
JobParameters paramJobParameters=JP.toJobParameters();
JobExecution jobExecution = jobLauncher.run(job, paramJobParameters);
log.info("{}_{} was completed successfully", job.getName(), jobExecution.getId());
} } catch (Exception e) {
log.error("Encountered job execution exception!");
}}}
And here is my batch config class :
#Value("#{jobParameters[CLASSAPP]}")
private String ClassApp;
#Scope("step")
#Bean
public JdbcCursorItemReader<FichierEclate> readerDB(){
JdbcCursorItemReader<FichierEclate> reader = new JdbcCursorItemReader<FichierEclate>();
reader.setDataSource(ds);
reader.setSql(query(ClassApp));
reader.setRowMapper(new FichierEclateRowMapper());
return reader;
}
i am also using another parameter in Quartz config :
#Value("#{jobParameters[CRON]}")
private String CRON_EXPRESSION;
#StepScope
#Bean
public JobDetailFactoryBean jobDetailFactoryBean() {
JobDetailFactoryBean factory = new JobDetailFactoryBean();
factory.setJobClass(QuartzJobLauncher.class);
Map map = new HashMap();
map.put("jobName", "JobFinal");
map.put("jobLauncher", jobLauncher);
map.put("jobLocator", jobLocator);
map.put("CRON_EXPRESSION", CRON_EXPRESSION );
factory.setJobDataAsMap(map);
factory.setGroup("etl_group");
factory.setName("etl_job");
return factory;}
I am also using the job parameter in the processor class :
#Value("#{jobParameters[CLASSAPP]}")
private String ClassApp;
#Scope("step")
#Override
public TdfFile process(FichierEclate item) throws Exception {
//some code and use the **CLASSAPP** variable }
i tried to use #StepScope But same problem !! i get this :
Error creating bean with name 'batchConfig': Unsatisfied dependency expressed through field 'ClassApp'; nested exception is org.springframework.beans.factory.BeanExpressionException: Expression parsing failed; nested exception is org.springframework.expression.spel.SpelEvaluationException: EL1008E: Property or field 'jobParameters' cannot be found on object of type 'org.springframework.beans.factory.config.BeanExpressionContext' - maybe not public or not valid?
Here is QuartzConfiguration class :
#Configuration
public class QuartzConfiguration {
#Value("#{jobParameters[CRON]}")
private String CRON_EXPRESSION;
#Autowired
private JobLauncher jobLauncher;
#Autowired
private JobLocator jobLocator;
public QuartzConfiguration() {
super();
}
#Bean
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) {
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
return jobRegistryBeanPostProcessor;
}
#Bean
#Scope(value="step", proxyMode=ScopedProxyMode.TARGET_CLASS)
public JobDetailFactoryBean jobDetailFactoryBean() {
JobDetailFactoryBean factory = new JobDetailFactoryBean();
factory.setJobClass(QuartzJobLauncher.class);
Map map = new HashMap();
map.put("jobName", "JobFinal");
map.put("jobLauncher", jobLauncher);
map.put("jobLocator", jobLocator);
map.put("CRON_EXPRESSION", CRON_EXPRESSION );
factory.setJobDataAsMap(map);
factory.setGroup("etl_group");
factory.setName("etl_job");
return factory;
}
// Job is scheduled after every 3 minutes
#Bean
public CronTriggerFactoryBean cronTriggerFactoryBean() {
CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean();
stFactory.setJobDetail(jobDetailFactoryBean().getObject());
stFactory.setStartDelay(3000);
stFactory.setName("cron_trigger");
stFactory.setGroup("cron_group");
stFactory.setCronExpression(CRON_EXPRESSION);
// stFactory.getJobDataMap().get(app);
return stFactory;
}
#Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
scheduler.setTriggers(cronTriggerFactoryBean().getObject());
return scheduler;
}}
And here is the jobLauncher class :
public class QuartzJobLauncher extends QuartzJobBean {
private static final Logger log = LoggerFactory.getLogger(QuartzJobLauncher.class);
#Autowired
private DataSource ds;
private String jobName;
private JobLauncher jobLauncher;
private JobLocator jobLocator;
public String getJobName() {
return jobName;
}
public void setJobName(String jobName) {
this.jobName = jobName;
}
public JobLauncher getJobLauncher() {
return jobLauncher;
}
public void setJobLauncher(JobLauncher jobLauncher) {
this.jobLauncher = jobLauncher;
}
public JobLocator getJobLocator() {
return jobLocator;
}
public void setJobLocator(JobLocator jobLocator) {
this.jobLocator = jobLocator;
}
#Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
try {
JdbcTemplate Jd = new JdbcTemplate(ds);
List<QuartzParameters> list=null;
list=Jd.query("select * from FLUX_INFO",new QuartzParametersMapper());
for (QuartzParameters i : list) {
Job job = jobLocator.getJob(jobName);
JobParametersBuilder JP = new JobParametersBuilder();
JP.addString("PAYS", i.getPAYS());
JP.addString("CRON", i.getCRON());
JP.addString("CLASSAPP",i.getCLASSAPP());
JobParameters paramJobParameters=JP.toJobParameters();
final JobExecution jobExecution = jobLauncher.run(job, paramJobParameters);
log.info("{}_{} was completed successfully", job.getName(), jobExecution.getId());
}} catch (Exception e) {
log.error("Encountered job execution exception!");
}}}
I tried to add #Scope(value="step", proxyMode=ScopedProxyMode.TARGET_CLASS) on classes directly or on Beans !! Both ways did not work !
Did anyone try a solution to solve this pliz ?!

Since you are injecting the job parameter in a field of your class, then #Scope("step") should be placed on the class itself, something like:
#Component
#Scope("step")
public class MyProcessor implements ItemProcessor<FichierEclate, TdfFile> {
#Value("#{jobParameters[CLASSAPP]}")
private String ClassApp;
#Override
public TdfFile process(FichierEclate item) throws Exception {
//some code and use the **CLASSAPP** variable
}
}
The same thing should be done for other classes where you want to inject jobParameters[CRON] and jobParameters[CLASSAPP].

Related

Spring batch with quartz configuration not working - Looking for spring metadata table instead of quartz table

I have requirement to develop a spring boot batch using quartz as scheduler.
I have created spring batch application and also configured quartz to trigger job and persist job/trigger data in quartz related RDBMS tables.
Spring boot application starts successfully but when it triggers the job as per cron config. Its throws below error.
2020-04-27 20:42:09.967 INFO 1460 --- [ main] c.b.g.batch.IemsBatchApplication : Started IemsBatchApplication in 12.112 seconds (JVM running for 13.22)
org.springframework.jdbc.BadSqlGrammarException: PreparedStatementCallback; bad SQL grammar [SELECT JOB_INSTANCE_ID, JOB_NAME from BATCH_JOB_INSTANCE where JOB_NAME = ? and JOB_KEY = ?]; nested exception is java.sql.SQLSyntaxErrorException: ORA-00942: table or view does not exist
I am not able to find the root cause that why application is trying to persist data in spring meta data table rather than quartz tables.
Quartz related tables are already created in my db.
Please help me.
Please find below the code for the same.
#Configuration
public class BatchSchedulerConfig {
#Autowired
#Qualifier("batchDataSource")
private DataSource batchDataSource;
#Autowired
JobLauncher jobLauncher;
#Autowired
JobLocator jobLocator;
#Bean
public JobDetailFactoryBean jobDetailFactoryBean() {
JobDetailFactoryBean jobDetailFactoryBean = new JobDetailFactoryBean();
jobDetailFactoryBean.setJobClass(BatchJobLauncherConfig.class);
Map<String, Object> map = new HashMap<String, Object>();
map.put("jobName", IEMSBatchConstant.MonthlyElectricityMeterReadingJob);
jobDetailFactoryBean.setJobDataAsMap(map);
jobDetailFactoryBean.setGroup("etl_group");
jobDetailFactoryBean.setName("etl_job");
return jobDetailFactoryBean;
}
#Bean
public CronTriggerFactoryBean cronTriggerFactoryBean(JobDetailFactoryBean jobDetailFactoryBean) {
CronTriggerFactoryBean cronTriggerFactoryBean = new CronTriggerFactoryBean();
cronTriggerFactoryBean.setJobDetail(jobDetailFactoryBean.getObject());
cronTriggerFactoryBean.setStartDelay(3000);
cronTriggerFactoryBean.setName("cron_trigger");
cronTriggerFactoryBean.setGroup("cron_group");
cronTriggerFactoryBean.setCronExpression("0 0/2 * 1/1 * ? *");
return cronTriggerFactoryBean;
}
#Bean
public SchedulerFactoryBean schedulerFactoryBean(CronTriggerFactoryBean cronTriggerFactoryBean) throws IOException {
SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
Map<String, Object> map = new HashMap<String, Object>();
map.put("joblocator", jobLocator);
map.put("JobLauncher", jobLauncher);
scheduler.setSchedulerContextAsMap(map);
scheduler.setTriggers(cronTriggerFactoryBean.getObject());
scheduler.setDataSource(batchDataSource);
scheduler.setQuartzProperties(quartzProperties());
// scheduler.setSchedulerName(schedulerName);
return scheduler;
}
public Properties quartzProperties() throws IOException {
PropertiesFactoryBean propertiesFactoryBean = new PropertiesFactoryBean();
propertiesFactoryBean.setLocation(new ClassPathResource("/quartz.properties"));
propertiesFactoryBean.afterPropertiesSet();
return propertiesFactoryBean.getObject();
}
}
#Configuration
#EnableConfigurationProperties
public class BatchBaseConfig {
private static final Logger log = LoggerFactory.getLogger(BatchBaseConfig.class);
#Bean
public JobLauncher jobLauncher(JobRepository jobRepository) throws Exception {
SimpleJobLauncher simpleJobLauncher = new SimpleJobLauncher();
simpleJobLauncher.setJobRepository(jobRepository);
return simpleJobLauncher;
}
#Bean
public JobRepository jobRepository(DataSource batchDataSource) throws Exception {
DataSourceTransactionManager batchTransactionManager = new DataSourceTransactionManager();
JobRepositoryFactoryBean jobRepositoryFactoryBean = new JobRepositoryFactoryBean();
batchTransactionManager.setDataSource(batchDataSource);
jobRepositoryFactoryBean.setTransactionManager(batchTransactionManager);
jobRepositoryFactoryBean.setDatabaseType(DatabaseType.ORACLE.getProductName());
//jobRepositoryFactoryBean.setIsolationLevelForCreate("ISOLATION_DEFAULT");
jobRepositoryFactoryBean.setDataSource(batchDataSource);
jobRepositoryFactoryBean.setTablePrefix("QRTZ_");
jobRepositoryFactoryBean.afterPropertiesSet();
return jobRepositoryFactoryBean.getObject();
}
#Bean(name = "batchDataSource")
#Primary
#ConfigurationProperties(prefix = "quartz")
public DataSource batchDataSource() {
DataSource batchDbSrc = DataSourceBuilder.create().build();
return batchDbSrc;
}
#Bean(name = "appDataSource")
#ConfigurationProperties(prefix = "app")
public DataSource appDataSource() {
DataSource appDbSrc = DataSourceBuilder.create().build();
return appDbSrc;
}
#Bean
public JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor(JobRegistry jobRegistry) {
JobRegistryBeanPostProcessor jobRegistryBeanPostProcessor = new JobRegistryBeanPostProcessor();
jobRegistryBeanPostProcessor.setJobRegistry(jobRegistry);
return jobRegistryBeanPostProcessor;
}
}
#Getter
#Setter
public class BatchJobLauncherConfig extends QuartzJobBean {
private static final Logger log = LoggerFactory.getLogger(BatchJobLauncherConfig.class);
private JobLauncher jobLauncher;
private JobLocator joblocator;
private String jobName;
#Override
protected void executeInternal(JobExecutionContext context) throws JobExecutionException {
try {
JobExecution jobExecution = jobLauncher.run(joblocator.getJob(jobName), new
JobParameters());
log.info("{}_{} was completed successfully", jobExecution.getJobConfigurationName(),
jobExecution.getId());
} catch (JobExecutionAlreadyRunningException | JobRestartException |
JobInstanceAlreadyCompleteException
| JobParametersInvalidException | NoSuchJobException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}
#Configuration
public class JobConfig {
private static final Logger log = LoggerFactory.getLogger(JobConfig.class);
#Autowired
private JobBuilderFactory jobBuilderFactory;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
private ReadingFromDB readingFromDB;
#Autowired
private ReadingFileWriter readingFileWriter;
#Qualifier(value = "meterReadingJob")
#Bean
public Job meterReadingJob() throws Exception {
log.info("Enter into meterReadingJob method ");
return this.jobBuilderFactory.get("meterReadingJob")
.start(createReadingFile()).build();
}
#Bean
public Step createReadingFile() throws Exception {
return this.stepBuilderFactory.get("createReadingFile").chunk(1)
.reader(readingFromDB).writer(readingFileWriter).build();
}
}
Application.properties
spring.batch.job.enabled=false
spring.main.allow-bean-definition-overriding=true
#Spring's default configuration to generate datasource
app.jdbcUrl=jdbc:oracle:thin:#//<Removed>
app.username=<Removed>
app.password=<Removed>
app.driverClassName=oracle.jdbc.OracleDriver
spring.app.jpa.database-platform=org.hibernate.dialect.Oracle10gDialect
#Quartz dataSource
quartz.jdbcUrl=jdbc:oracle:thin:#//<Removed>
quartz.username=<Removed>
quartz.password=<Removed>
quartz.driverClassName=oracle.jdbc.OracleDriver
Quartz.properties
#scheduler name will be "MyScheduler"
org.quartz.scheduler.instanceName=MyNewScheduler
org.quartz.scheduler.instanceId=AUTO
#maximum of 3 jobs can be run simultaneously
org.quartz.threadPool.class=org.quartz.simpl.SimpleThreadPool
org.quartz.threadPool.threadCount=50
#Quartz persistent jobStore config
org.quartz.jobStore.class=org.quartz.impl.jdbcjobstore.JobStoreTX
org.quartz.jobStore.driverDelegateClass=org.quartz.impl.jdbcjobstore.StdJDBCDelegate
org.quartz.jobStore.tablePrefix=QRTZ_
#org.quartz.jobStore.dataSource=batchDataSource
org.quartz.jobStore.useProperties=false
org.quartz.jobStore.isClustered=false
Both datasources are getting created and entries are also going for triggers and jobs in datasource names batchDataSource.
Issue comes when job gets triggered and batch tries to insert job details in DB.
Thanks in advance.

Spring Boot + Spring Batch Multiple Job Creation and Scheduling

I created a Spring Boot with Spring Batch Application and Scheduling. When i create only one job, things are working fine . But when i try to create another job using the modular approach, I am getting few errors like reader is already closed and some errors related to version even though i am using different readers. The jobs and it's step are running many times and they are getting duplicated.
Can anyone Please guide me how to resolve these issues and run the jobs in a parallel way independent of each other ?
Below are the configuration Classes :
ModularJobConfiguration.java , DeptBatchConfiguration.java and CityBatchConfiguration.java and BatchScheduler.java
#Configuration
#EnableBatchProcessing(modular=true)
public class ModularJobConfiguration {
#Bean
public ApplicationContextFactory firstJob() {
return new GenericApplicationContextFactory(DeptBatchConfiguration.class);
}
#Bean
public ApplicationContextFactory secondJob() {
return new GenericApplicationContextFactory(CityBatchConfiguration.class);
}
}
#Configuration
#EnableBatchProcessing
#Import({BatchScheduler.class})
public class DeptBatchConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(DeptBatchConfiguration.class);
#Autowired
private SimpleJobLauncher jobLauncher;
#Autowired
public JobBuilderFactory jobBuilderFactory;
#Autowired
public StepBuilderFactory stepBuilderFactory;
#Autowired
public JobExecutionListener listener;
public ItemReader<DepartmentModelReader> deptReaderSO;
#Autowired
#Qualifier("dataSourceReader")
private DataSource dataSourceReader;
#Autowired
#Qualifier("dataSourceWriter")
private DataSource dataSourceWriter;
#Scheduled(cron = "0 0/1 * * * ?")
public void performFirstJob() throws Exception {
long startTime = System.currentTimeMillis();
LOGGER.info("Job1 Started at :" + new Date());
JobParameters param = new JobParametersBuilder().addString("JobID1",String.valueOf(System.currentTimeMillis())).toJobParameters();
JobExecution execution = (JobExecution) jobLauncher.run(importDeptJob(jobBuilderFactory,stepdept(deptReaderSO,customWriter()),listener), param);
long endTime = System.currentTimeMillis();
LOGGER.info("Job1 finished at " + (endTime - startTime) / 1000 + " seconds with status :" + execution.getExitStatus());
}
#Bean
public ItemReader<DepartmentModelReader> deptReaderSO() {
//LOGGER.info("Inside deptReaderSO Method");
JdbcCursorItemReader<DepartmentModelReader> deptReaderSO = new JdbcCursorItemReader<>();
//deptReaderSO.setSql("select id, firstName, lastname, random_num from reader");
deptReaderSO.setSql("SELECT DEPT_CODE,DEPT_NAME,FULL_DEPT_NAME,CITY_CODE,CITY_NAME,CITY_TYPE_NAME,CREATED_USER_ID,CREATED_G_DATE,MODIFIED_USER_ID,MODIFIED_G_DATE,RECORD_ACTIVITY,DEPT_CLASS,DEPT_PARENT,DEPT_PARENT_NAME FROM TBL_SAMPLE_SAFTY_DEPTS");
deptReaderSO.setDataSource(dataSourceReader);
deptReaderSO.setRowMapper(
(ResultSet resultSet, int rowNum) -> {
if (!(resultSet.isAfterLast()) && !(resultSet.isBeforeFirst())) {
DepartmentModelReader recordSO = new DepartmentModelReader();
recordSO.setDeptCode(resultSet.getString("DEPT_CODE"));
recordSO.setDeptName(resultSet.getString("DEPT_NAME"));
recordSO.setFullDeptName(resultSet.getString("FULL_DEPT_NAME"));
recordSO.setCityCode(resultSet.getInt("CITY_CODE"));
recordSO.setCityName(resultSet.getString("CITY_NAME"));
recordSO.setCityTypeName(resultSet.getString("CITY_TYPE_NAME"));
recordSO.setCreatedUserId(resultSet.getInt("CREATED_USER_ID"));
recordSO.setCreatedGDate(resultSet.getDate("CREATED_G_DATE"));
recordSO.setModifiedUserId(resultSet.getString("MODIFIED_USER_ID"));
recordSO.setModifiedGDate(resultSet.getDate("MODIFIED_G_DATE"));
recordSO.setRecordActivity(resultSet.getInt("RECORD_ACTIVITY"));
recordSO.setDeptClass(resultSet.getInt("DEPT_CLASS"));
recordSO.setDeptParent(resultSet.getString("DEPT_PARENT"));
recordSO.setDeptParentName(resultSet.getString("DEPT_PARENT_NAME"));
// LOGGER.info("RowMapper record : {}", recordSO.getDeptCode() +" | "+recordSO.getDeptName());
return recordSO;
} else {
LOGGER.info("Returning null from rowMapper");
return null;
}
});
return deptReaderSO;
}
#Bean
public ItemProcessor<DepartmentModelReader, DepartmentModelWriter> processor() {
//LOGGER.info("Inside Processor Method");
return new RecordProcessor();
}
#Bean
public ItemWriter<DepartmentModelWriter> customWriter(){
//LOGGER.info("Inside customWriter Method");
return new CustomItemWriter();
}
#Bean
public Job importDeptJob(JobBuilderFactory jobs, Step stepdept,JobExecutionListener listener){
return jobs.get("importDeptJob")
.incrementer(new RunIdIncrementer())
.listener(listener())
.flow(stepdept).end().build();
}
#Bean
public Step stepdept(ItemReader<DepartmentModelReader> deptReaderSO,
ItemWriter<DepartmentModelWriter> writerSO) {
LOGGER.info("Inside stepdept Method");
return stepBuilderFactory.get("stepdept").<DepartmentModelReader, DepartmentModelWriter>chunk(5)
.reader(deptReaderSO).processor(processor()).writer(customWriter()).transactionManager(platformTransactionManager(dataSourceWriter)).build();
}
#Bean
public JobExecutionListener listener() {
return new JobCompletionNotificationListener();
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
#Bean
public BatchWriteService batchWriteService() {
return new BatchWriteService();
}
#Bean
public PlatformTransactionManager platformTransactionManager(#Qualifier("dataSourceWriter") DataSource dataSourceWriter) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setDataSource(dataSourceWriter);
return transactionManager;
}
}
#Configuration
#EnableBatchProcessing
#Import({BatchScheduler.class})
public class CityBatchConfiguration {
private static final Logger LOGGER = LoggerFactory.getLogger(CityBatchConfiguration.class);
#Autowired
private SimpleJobLauncher jobLauncher;
#Autowired
public JobBuilderFactory jobBuilderFactory;
#Autowired
public StepBuilderFactory stepBuilderFactory;
#Autowired
public JobExecutionListener listener;
public ItemReader<CitiesModelReader> citiesReaderSO;
#Autowired
#Qualifier("dataSourceReader")
private DataSource dataSourceReader;
#Autowired
#Qualifier("dataSourceWriter")
private DataSource dataSourceWriter;
#Scheduled(cron = "0 0/1 * * * ?")
public void performSecondJob() throws Exception {
long startTime = System.currentTimeMillis();
LOGGER.info("\n Job2 Started at :" + new Date());
JobParameters param = new JobParametersBuilder().addString("JobID2",String.valueOf(System.currentTimeMillis())).toJobParameters();
JobExecution execution = (JobExecution) jobLauncher.run(importCitiesJob(jobBuilderFactory,stepcity(citiesReaderSO,customCitiesWriter()),listener), param);
long endTime = System.currentTimeMillis();
LOGGER.info("Job2 finished at " + (endTime - startTime) / 1000 + " seconds with status :" + execution.getExitStatus());
}
#Bean
public ItemReader<CitiesModelReader> citiesReaderSO() {
//LOGGER.info("Inside readerSO Method");
JdbcCursorItemReader<CitiesModelReader> readerSO = new JdbcCursorItemReader<>();
readerSO.setSql("SELECT CITY_CODE,CITY_NAME,PARENT_CITY,CITY_TYPE,CITY_TYPE_NAME,CREATED_G_DATE,CREATED_USER_ID,MODIFIED_G_DATE,MODIFIED_USER_ID,RECORD_ACTIVITY FROM TBL_SAMPLE_SAFTY_CITIES");
readerSO.setDataSource(dataSourceReader);
readerSO.setRowMapper(
(ResultSet resultSet, int rowNum) -> {
if (!(resultSet.isAfterLast()) && !(resultSet.isBeforeFirst())) {
CitiesModelReader recordSO = new CitiesModelReader();
recordSO.setCityCode(resultSet.getLong("CITY_CODE"));
recordSO.setCityName(resultSet.getString("CITY_NAME"));
recordSO.setParentCity(resultSet.getInt("PARENT_CITY"));
recordSO.setCityType(resultSet.getString("CITY_TYPE"));
recordSO.setCityTypeName(resultSet.getString("CITY_TYPE_NAME"));
recordSO.setCreatedGDate(resultSet.getDate("CREATED_G_DATE"));
recordSO.setCreatedUserId(resultSet.getString("CREATED_USER_ID"));
recordSO.setModifiedGDate(resultSet.getDate("MODIFIED_G_DATE"));
recordSO.setModifiedUserId(resultSet.getString("MODIFIED_USER_ID"));
recordSO.setRecordActivity(resultSet.getInt("RECORD_ACTIVITY"));
//LOGGER.info("RowMapper record : {}", recordSO.toString());
return recordSO;
} else {
LOGGER.info("Returning null from rowMapper");
return null;
}
});
return readerSO;
}
#Bean
public ItemProcessor<CitiesModelReader,CitiesModelWriter> citiesProcessor() {
//LOGGER.info("Inside Processor Method");
return new RecordCitiesProcessor();
}
#Bean
public ItemWriter<CitiesModelWriter> customCitiesWriter(){
LOGGER.info("Inside customCitiesWriter Method");
return new CustomCitiesWriter();
}
#Bean
public Job importCitiesJob(JobBuilderFactory jobs, Step stepcity,JobExecutionListener listener) {
LOGGER.info("Inside importCitiesJob Method");
return jobs.get("importCitiesJob")
.incrementer(new RunIdIncrementer())
.listener(listener())
.flow(stepcity).end().build();
}
#Bean
public Step stepcity(ItemReader<CitiesModelReader> readerSO,
ItemWriter<CitiesModelWriter> writerSO) {
LOGGER.info("Inside stepCity Method");
return stepBuilderFactory.get("stepcity").<CitiesModelReader, CitiesModelWriter>chunk(5)
.reader(readerSO).processor(citiesProcessor()).writer(customCitiesWriter()).transactionManager(platformTransactionManager(dataSourceWriter)).build();
}
#Bean
public JobExecutionListener listener() {
return new JobCompletionNotificationListener();
}
#Bean
public JdbcTemplate jdbcTemplate(DataSource dataSource) {
return new JdbcTemplate(dataSource);
}
#Bean
public BatchWriteService batchWriteService() {
return new BatchWriteService();
}
#Bean
public PlatformTransactionManager platformTransactionManager(#Qualifier("dataSourceWriter") DataSource dataSourceWriter) {
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setDataSource(dataSourceWriter);
return transactionManager;
}
}
#Configuration
#EnableScheduling
public class BatchScheduler {
private static final Logger LOGGER = LoggerFactory.getLogger(BatchScheduler.class);
#Bean
public ResourcelessTransactionManager resourcelessTransactionManager() {
return new ResourcelessTransactionManager();
}
#Bean
public MapJobRepositoryFactoryBean mapJobRepositoryFactory(
ResourcelessTransactionManager txManager) throws Exception {
LOGGER.info("Inside mapJobRepositoryFactory method");
MapJobRepositoryFactoryBean factory = new
MapJobRepositoryFactoryBean(txManager);
factory.afterPropertiesSet();
return factory;
}
#Bean
public JobRepository jobRepository(
MapJobRepositoryFactoryBean factory) throws Exception {
LOGGER.info("Inside jobRepository method");
return factory.getObject();
}
#Bean
public SimpleJobLauncher jobLauncher(JobRepository jobRepository) {
LOGGER.info("Inside jobLauncher method");
SimpleJobLauncher launcher = new SimpleJobLauncher();
launcher.setJobRepository(jobRepository);
final SimpleAsyncTaskExecutor simpleAsyncTaskExecutor = new SimpleAsyncTaskExecutor();
launcher.setTaskExecutor(simpleAsyncTaskExecutor);
return launcher;
}
}
Your readers are not thread safe and not step scoped. Because of that, you're running into concurrency issues. Configure each of your stateful ItemReaders (the ones that implement ItemStream like the JdbcCursorItemReader), to be step scoped by adding the #StepScope annotation and things should work fine.

Failed to run job based on schedule

I'm tying to run the batch based on schedule.I have used scheduled annotation & cron expression. Batch is running only once. No error is getting displayed. I have added maven dependency for quartz.I have not added any XML file.
#EnableAutoConfiguration(exclude = { DataSourceAutoConfiguration.class,SwaggerConfig.class,
WebMvcAutoConfiguration.class,RepositoryRestMvcAutoConfiguration.class })
#EnableScheduling
#ComponentScan
public class BatchApplication {
public static void main(String[] args) throws Exception {
SpringApplication app = new SpringApplication(BatchApplication.class);
app.setWebEnvironment(false);
ConfigurableApplicationContext ctx = app.run(args);
System.out.println(ctx.getBean(DataSource.class));
JobLauncher jobLauncher = ctx.getBean(JobLauncher.class);
Job addLeaveAllocationJob = ctx.getBean("addLeaveAllocationJob", Job.class);
JobParameters jobParameters = new JobParametersBuilder().addDate("date", new Date())
.toJobParameters();
JobExecution jobExecution = jobLauncher.run(addLeaveAllocationJob, jobParameters);
BatchStatus batchStatus = jobExecution.getStatus();
while(batchStatus.isRunning()){
System.out.println("*** Still Running ************");
Thread.sleep(2000);
}
}
}
I have job class which is scheduled with #scheduled annotation with cron expression.
#Configuration
#EnableBatchProcessing
#Component
public class LeaveAllocationJobConfiguration {
#Autowired
private JobBuilderFactory jobs;
#Autowired
private StepBuilderFactory stepBuilderFactory;
#Autowired
private EntityManagerFactory entityManagerFactory;
#Bean
public ItemReader<Employee> reader() {
JpaPagingItemReader<Employee> employeeReader = new JpaPagingItemReader<Employee>();
employeeReader.setEntityManagerFactory(entityManagerFactory);
employeeReader.setQueryString("from Employee");
return employeeReader;
}
#Bean
#Scheduled(cron="0 0/1 * 1/1 * ? *")
public Job addLeaveAllocationJob() {
System.out.println("Hello");
return jobs.get("addLeaveAllocationJob").listener(protocolListener()).start(step()).build();
}
#Bean
public Step step() {
// important to be one in this case to commit after every line read
return stepBuilderFactory.get("step").<Employee, EmployeeDTO> chunk(1).reader(reader()).processor(processor())
.writer(writer()).build();
}
/**
* #return
*/
#Bean
public ItemWriter<? super EmployeeDTO> writer() {
return new ItemWriter<EmployeeDTO>() {
#Override
public void write(List<? extends EmployeeDTO> items) throws Exception {
System.out.println("Processing " + items);
}
};
}
#Bean
public ItemProcessor<Employee, EmployeeDTO> processor() {
return new ItemProcessor<Employee, EmployeeDTO>() {
#Override
public EmployeeDTO process(Employee employee) throws Exception {
return new EmployeeDTO(employee);
}
};
}
#Bean
public ProtocolListener protocolListener() {
return new ProtocolListener();
}
}
Please help me to solve the issue
Chek this link.enter link description here

Job doesn't reschedule immediately when triggers update in quartz

I'm trying to develop an spring application using Quartz which reads trigger time for Job from database and run it. I have managed to implement this scenario successfully.However, during job execution when i update the trigger time in database, it doesn't run the trigger the job according to the new time but it always run old time.
Code:
#Configuration
#ComponentScan
public class QuartzConfiguration {
#Bean
public MethodInvokingJobDetailFactoryBean methodInvokingJobDetailFactoryBean() {
MethodInvokingJobDetailFactoryBean obj = new MethodInvokingJobDetailFactoryBean();
obj.setTargetBeanName("jobone");
obj.setTargetMethod("myTask");
return obj;
}
#Autowired
public TestModelRepository testModelRepository;
#Bean
public JobDetailFactoryBean jobDetailFactoryBean(){
JobDetailFactoryBean factory = new JobDetailFactoryBean();
factory.setJobClass(MyJobTwo.class);
TestModel result = testModelRepository.findOne((long) 1);
factory.setGroup("mygroup");
factory.setName("myjob");
return factory;
}
public TestModelRepository getTestModelRepository() {
return testModelRepository;
}
public void setTestModelRepository(TestModelRepository testModelRepository) {
this.testModelRepository = testModelRepository;
}
#Bean
public CronTriggerFactoryBean cronTriggerFactoryBean(){
CronTriggerFactoryBean stFactory = new CronTriggerFactoryBean();
stFactory.setJobDetail(jobDetailFactoryBean().getObject());
//stFactory.setStartDelay(3000;
stFactory.setName("mytrigger");
stFactory.setGroup("mygroup");
TestModel result = testModelRepository.findOne((long) 1);
stFactory.setCronExpression(result.getCronTime());
return stFactory;
}
#Bean
public SchedulerFactoryBean schedulerFactoryBean() {
SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
scheduler.setTriggers(cronTriggerFactoryBean().getObject());
return scheduler;
}
}
Job:
#PersistJobDataAfterExecution
#DisallowConcurrentExecution
public class MyJobTwo extends QuartzJobBean {
public static final String COUNT = "count";
private static URI jiraServerUri = URI.create("");
JiraRestClient restClient = null;
private String name;
protected void executeInternal(JobExecutionContext ctx) throws JobExecutionException {
final AsynchronousJiraRestClientFactory factory = new AsynchronousJiraRestClientFactory();
restClient = factory.createWithBasicHttpAuthentication(jiraServerUri,"", "");
}
public void setName(String name) {
this.name = name;
}
Any idea?
Just in case if someone needs solution.
SchedulerFactoryBean scheduler = new SchedulerFactoryBean();
scheduler.setOverwriteExistingJobs(true);

spring batch with annotations

I'm currently trying to create a batch with the spring annotations but the batch is never called. No error occurs, my batch isn't called. Its a simple batch that retrieves values from the database and add messages in a queue (rabbitmq).
The main configuration class:
#Configuration
#EnableBatchProcessing
public class BatchInfrastructureConfiguration {
#Bean
public JobLauncher getJobLauncher() throws Exception {
SimpleJobLauncher jobLauncher = new SimpleJobLauncher();
jobLauncher.setJobRepository(getJobRepository());
jobLauncher.afterPropertiesSet();
return jobLauncher;
}
public JobRepository getJobRepository() throws Exception {
MapJobRepositoryFactoryBean factory = new MapJobRepositoryFactoryBean();
factory.setTransactionManager(new ResourcelessTransactionManager());
factory.afterPropertiesSet();
return (JobRepository) factory.getObject();
}
}
The configuration class specific to my batch
#Configuration
#Import(BatchInfrastructureConfiguration.class)
public class PurchaseStatusBatchConfiguration {
#Inject
private JobBuilderFactory jobBuilders;
#Inject
private StepBuilderFactory stepBuilders;
#Bean
public Job purchaseStatusJob(){
return jobBuilders.get("purchaseStatusJob")
.start(step())
.build();
}
#Bean
public Step step(){
return stepBuilders.get("purchaseStatusStep")
.tasklet(new PurchaseStatusBatch())
.build();
}
}
The batch class:
public class PurchaseStatusBatch implements Tasklet {
#Inject
private PurchaseRepository purchaseRepository;
#Inject
#Qualifier(ApplicationConst.BEAN_QUALIFIER_PURCHASE_QUEUE)
private RabbitTemplate rabbitTemplate;
#Override
public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception {
PurchaseDto purchaseDto;
PurchaseMessage purchaseMessage;
List<Purchase> notVerifiedPurchase = purchaseRepository.findByVerified(false);
for (Purchase purchase : notVerifiedPurchase) {
purchaseDto = new PurchaseDto();
purchaseDto.setOrderId(purchase.getOrderId());
purchaseDto.setProductId(purchase.getProductId());
purchaseDto.setPurchaseToken(purchase.getPurchaseToken());
purchaseDto.setUserScrapbookKey(purchase.getUserScrapbookKey());
purchaseMessage = new PurchaseMessage();
purchaseMessage.setPurchaseDto(purchaseDto);
rabbitTemplate.convertAndSend(purchaseMessage);
}
return null;
}
}
The job runner (class calling the batch):
#Service
public class PurchaseStatusJobRunner {
#Inject
private JobLocator jobLocator;
#Inject
private JobLauncher jobLauncher;
//#Scheduled(fixedDelay = 3000L)
//#Scheduled(cron="* * * * *") // every 1 minute
#Scheduled(fixedDelay = 3000L)
public void runJob() throws JobExecutionAlreadyRunningException, JobRestartException, JobInstanceAlreadyCompleteException, JobParametersInvalidException, NoSuchJobException {
jobLauncher.run(jobLocator.getJob("purchaseStatusJob"), new JobParameters());
}
}
Short answer: The problem is that your PurchaseStatusBatch instance is not a spring bean... then all its attributes are null (they have not been injected)
Try this :
#Bean
public Step step(){
return stepBuilders.get("purchaseStatusStep")
.tasklet(purchaseStatusBatch())
.build();
}
#Bean
public PurchaseStatusBatch purchaseStatusBatch() {
return new PurchaseStatusBatch()
}
When you want to have feedback on your job execution, just use the JobExecution instance returned by the JobLauncher. You can get the ExitStatus, you can get all exceptions catched by the JobLauncher, and more information.
Another solution to have feedback would be providing a real database to your JobRepository, and then check execution statuses in it.

Resources