2
votes

I have a spring mvc application with spring batch integrated. My spring batch jobs get executed via cron triggers.

I have two batch jobs definied in my xml. The second batch jobs works fine but when I execute the first batch job it executed the second.

I think I am registering my jobs incorrectly. Can someone help me with what might be wrong.

thanks

2nd job definition (job-bulletin-bar-msg-update.xml)...

<job id="job-bulletin-bar-msg-update" xmlns="http://www.springframework.org/schema/batch">
    <step id="step1">
        <tasklet>
            <chunk 
                reader="bulletinBarUpdateJdbcCursorItemReader" 
                writer="bulletinBarUpdateItemWriter" 
                commit-interval="1000" />
        </tasklet>
    </step>
</job>

1st job definition (job-daily-tran-counts.xml)...

<job id="job-daily-tran-counts" xmlns="http://www.springframework.org/schema/batch">
    <step id="step1">
        <tasklet>
            <chunk 
                reader="dailyTranCountJdbcCursorItemReader" 
                writer="dailyTranCountItemWriter" 
                commit-interval="1000" />
        </tasklet>
    </step>
</job>

Adding job to scheduler and registry....

<beans profile="pre,prod">
    <!-- jobs -->
    <import resource="./jobs/job-daily-tran-counts.xml" />
    <import resource="./jobs/job-bulletin-bar-msg-update.xml" />    

    <bean class="org.springframework.scheduling.quartz.SchedulerFactoryBean">
        <property name="jobDetails">
           <list>
              <ref bean="dailyTranCountJobDetail" />
              <ref bean="bulletinBarMsgUpdateJobDetail" />
           </list>
        </property>
        <property name="triggers">
           <list>
              <ref bean="dailyTranCountCronTrigger" />
              <ref bean="bulletinBarMsgUpdateCronTrigger" />
           </list>
        </property>
    </bean>

    <!-- scheduling properties -->
    <util:properties id="batchProps" location="classpath:batch.properties" />
    <context:property-placeholder properties-ref="batchProps" />        

    <!-- triggers -->
    <bean id="dailyTranCountCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail" ref="dailyTranCountJobDetail" />
        <property name="cronExpression" value="#{batchProps['cron.dailyTranCounts']}" />
    </bean>


    <bean id="bulletinBarMsgUpdateCronTrigger" class="org.springframework.scheduling.quartz.CronTriggerBean">
        <property name="jobDetail" ref="bulletinBarMsgUpdateJobDetail" />
        <property name="cronExpression" value="#{batchProps['cron.bulletinBarUpdateMsg']}" />
    </bean>     



    <!-- job detail -->
    <bean id="dailyTranCountJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="jobClass" value="com.myer.reporting.batch.JobLauncherDetails" />
        <property name="group" value="quartz-batch" />
        <property name="jobDataAsMap">
            <map>
                <entry key="jobName" value="job-daily-tran-counts" />
                <entry key="jobLocator" value-ref="jobRegistry" />
                <entry key="jobLauncher" value-ref="jobLauncher" />
            </map>
        </property>
    </bean> 

    <bean id="bulletinBarMsgUpdateJobDetail" class="org.springframework.scheduling.quartz.JobDetailBean">
        <property name="jobClass" value="com.myer.reporting.batch.JobLauncherDetails" />
        <property name="group" value="quartz-batch" />
        <property name="jobDataAsMap">
            <map>
                <entry key="jobName" value="job-bulletin-bar-msg-update" />
                <entry key="jobLocator" value-ref="jobRegistry" />
                <entry key="jobLauncher" value-ref="jobLauncher" />
            </map>
        </property>
    </bean>

</beans>            

Here is my job launcher details class. I just copied it from somewhere else...

public class JobLauncherDetails extends QuartzJobBean {

    static final String JOB_NAME = "jobName";

    private JobLocator jobLocator;

    private JobLauncher jobLauncher;

    public void setJobLocator(JobLocator jobLocator) {
        this.jobLocator = jobLocator;
    }

    public void setJobLauncher(JobLauncher jobLauncher) {
        this.jobLauncher = jobLauncher;
    }

    @SuppressWarnings("unchecked")
    protected void executeInternal(JobExecutionContext context) {

        Map<String, Object> jobDataMap = context.getMergedJobDataMap();

        String jobName = (String) jobDataMap.get(JOB_NAME);

        JobParameters jobParameters = getJobParametersFromJobMap(jobDataMap);

        try {
            jobLauncher.run(jobLocator.getJob(jobName), jobParameters);
        } catch (JobExecutionException e) {
            e.printStackTrace();
        }
    }

    //get params from jobDataAsMap property, job-quartz.xml
    private JobParameters getJobParametersFromJobMap(Map<String, Object> jobDataMap) {

        JobParametersBuilder builder = new JobParametersBuilder();

        for (Entry<String, Object> entry : jobDataMap.entrySet()) {
            String key = entry.getKey();
            Object value = entry.getValue();
            if (value instanceof String && !key.equals(JOB_NAME)) {
                builder.addString(key, (String) value);
            } else if (value instanceof Float || value instanceof Double) {
                builder.addDouble(key, ((Number) value).doubleValue());
            } else if (value instanceof Integer || value instanceof Long) {
                builder.addLong(key, ((Number) value).longValue());
            } else if (value instanceof Date) {
                builder.addDate(key, (Date) value);
            } else {
                // JobDataMap contains values which are not job parameters
                // (ignoring)
            }
        }

        //need unique job parameter to rerun the same job
        builder.addDate("run date", new Date());

        return builder.toJobParameters();

    }

}

Here is my batch.properties...

#http://quartz-scheduler.org/documentation/quartz-1.x/tutorials/crontrigger
cron.dailyTranCounts=0 15 07 * * ? *
cron.bulletinBarUpdateMsg=0 30 07 * * ? *

Some more info. To try and find out more I put a log on org.springframework.batch.core.launch.support.SimpleJobLauncher.

When I had only the first job enabled in my spring config the log shows that job-daily-tran-counts takes roughly 2.5 minutes to execute...

[INFO] 2014-03-19 07:15:00,187 org.springframework.batch.core.launch.support.SimpleJobLauncher run - Job: [FlowJob: [name=job-daily-tran-counts]] launched with the following parameters: [{run date=1395173700052}]
[INFO] 2014-03-19 07:17:43,934 org.springframework.batch.core.launch.support.SimpleJobLauncher run - Job: [FlowJob: [name=job-daily-tran-counts]] completed with the following parameters: [{run date=1395173700052}] and the following status: [COMPLETED]

When I had only the both jobs enabled in my spring config the log shows that job-daily-tran-counts takes roughly only 8 milliseconds when it should take longer. i.e. It is doing nothing...

[INFO] 2014-04-15 07:15:00,225 org.springframework.batch.core.launch.support.SimpleJobLauncher run - Job: [FlowJob: [name=job-daily-tran-counts]] launched with the following parameters: [{run date=1397510100128}]
[INFO] 2014-04-15 07:15:08,977 org.springframework.batch.core.launch.support.SimpleJobLauncher run - Job: [FlowJob: [name=job-daily-tran-counts]] completed with the following parameters: [{run date=1397510100128}] and the following status: [COMPLETED]
[INFO] 2014-04-15 07:30:00,009 org.springframework.batch.core.launch.support.SimpleJobLauncher run - Job: [FlowJob: [name=job-bulletin-bar-msg-update]] launched with the following parameters: [{run date=1397511000007}]
[INFO] 2014-04-15 07:30:05,217 org.springframework.batch.core.launch.support.SimpleJobLauncher run - Job: [FlowJob: [name=job-bulletin-bar-msg-update]] completed with the following parameters: [{run date=1397511000007}] and the following status: [COMPLETED]
3
Can you show us com.myer.reporting.batch.JobLauncherDetails as well? - Morfic
thanks for helping me. I've added the class to the bottom of the post. - Richie
Everything looks clean.Copying your config I've made a simpler example which just logs the job name, and it outputs correctly both the jobs, cycling them even when I had it running a pool of only 1 thread. Can you also post batch.properties or the cron expressions? How did you figure out that it was executing only the second job? - Morfic
The reason that I say it is only executing the second job is because I have breakpoints on the jdbcItemReaders in my first job and my second job. When I only have the first job configured in my xml config the breakpoint lands in the jdbcItemReader for the first job but when I have two jobs configured in my xml config the breakpoint lands in the second jdbcItemReader even though it seems to pick up the right job from the job registry. I have put the log on org.springframework.batch.core.launch.support. Will add the output - Richie
Well from the point of view of quartz and spring batch, it seems that the scheduling and job launching is working fine. You mean to say that if you disable the break point in your second jdbc item reader, the debugger won't pause and jump to the breakpoint in the first one? - Morfic

3 Answers

2
votes

I had a similar issue. What worked for me is renaming the step-ids so that they are unique. Worth a shot

0
votes

I had a similar issue, this is spring batch version 4.2.1.RELEASE running with spring boot version 2.1.10.RELEASE powered by spring framework version 5.1.11.RELEASE. So there is a case here (probably) for what happens when the framework is "unequally yorked to contemporaries". Another thing to consider is the persistent nature of job repositories, meaning at some point the job will be calling the wrong steps. This took a lot of debugging break points especially around the job-launcher. So what I did was arbitrarily change the names of the steps. This would in my hypothesis force the framework to detect changes in the ids of steps and refresh the definitions in the database. It worked. Still to find out if the step-id-name-calling problem can fix itself if I stick to spring boot's version of spring batch.

0
votes

I have the same problem, had to rename all steps.

read somewhere about @EnableBatchProcessing(modular=true)

It might keep the jobs in seperate 'context'