Results 1 to 10 of 10

Thread: Load batch job config at runtime

  1. #1

    Default Load batch job config at runtime

    Hi,

    I am already using Spring Batch for a limited number of jobs, but I am in the process of transferring all jobs from our custom batch framework to our Spring Batch implementation.

    The problem is that there are close to 50 jobs in our custom framework. If I put it into our current implementation, all spring configs for all jobs will be loaded at batch startup. Not only will this take an obscene amount of time, but it will also place quite a bit of stress on the heap space etc.

    Is there a way to configure the jobs to run, but load the specific spring configs for that job at runtime? That way, once the job has completed, the context can be closed and objects garbage collected as required.

    My initial solution is to override SimpleJob or FlowJob and more specifically override the doExecute(JobExecution execution) method. This will load the Job specific spring context, set the steps in the parent *Job and then continue with the execution logic.

    My main queries are:
    • Will this work?
    • Does anyone have any better solutions?


    Thanks.

  2. #2
    Join Date
    Jun 2005
    Posts
    4,230

    Default

    There is a JobLoader interface in Spring Batch. It wasn't designed for this use case, but you might be able to make it work (there is a method for loading one ApplicationContext but not for unloading a single one because it wasn't needed yet). I'd be interested to hear how it goes if you try it because I can imagine all sorts of potential memory leaks.

  3. #3

    Default

    I've been prototyping this all day and I've come up with a solution based on overriding SimpleJob.

    By splitting the <batch:job ...../> defintion from the <step....> definitions, I was able to load all jobs (2 at the moment) at startup, but the steps were not loaded until a job instance was actually started.
    By subclassing the SimpleJob, I could create it in the spring context as:

    Code:
    <bean id="jobA" class="ContextLoadingSimpleJob" parent="dailyJobParent" >
    		<property name="contexts">
    			<list>
    				<value>spring/configA.xml</value>
    				<value>spring/configB.xml</value>
    			</list>
    		</property>
    </bean>
    This is still picked up by the JobRegistrar and so still available for job creation, but does not have the overhead of having all of its objects created thus far.

    Then, once a Job Instance is created and the job is run, the doExecute method in Simplejob is overridden in ContextLoadingSimpleJob as:

    Code:
    @SuppressWarnings("unchecked")
    	@Override
    	protected void doExecute(JobExecution execution) throws JobInterruptedException, JobRestartException, StartLimitExceededException {
    		ConfigurableApplicationContext context = new ClassPathXmlApplicationContext(contexts.toArray(new String[0]), applicationContext);
    		setSteps((List<Step>) context.getBean("steps"));
    		super.doExecute(execution);
    		context.close();
    	}
    Therefore placing a contract on the spring contexts configured earlier that there must be a List<String> of Step objects to be used by the ContextLoadingSimpleJob.

    As I mentioned before, I am only prototyping today so haven't performed any memory analysis on this yet, but once the Job has finished, the context will be closed and everything that isn't being used will hopefully be garbage collected.

  4. #4
    Join Date
    Jun 2005
    Posts
    4,230

    Default

    Interesting. You wouldn't have to give up the Batch XML namespace features if you used FlowJob and injected a Flow. Does that work?

    You probably want to put that context.close() in a finally block:

    Code:
    ConfigurableApplicationContext context = ...
    try {
      setSteps((List<Step>) context.getBean("steps"));
      super.doExecute(execution);
    } finally {
      context.close();
    }

  5. #5

    Default

    Thanks for the tip. How would I use this by injecting a Flow?

  6. #6
    Join Date
    Jun 2005
    Posts
    4,230

    Default

    FlowJob has a setFlow() method. You could define a <flow.../> with your step logic in the XML that you load in the overridden doExecute().

    You might need to think about what will happen when two executions happen concurrently. It seems like it would be safe as long as you are prepared to synchronize the execution, but maybe you can be more relaxed.

  7. #7

    Default

    I think in this context I will want to prevent concurrent execution. As these are batch jobs putting data into a database, they are sometimes required to delete from data first, which wouldn't play nice if it was done concurrently. It could be useful for future projects though.

    Thanks for your tips.

  8. #8
    Join Date
    May 2010
    Posts
    5

    Default

    very good idea i will share with my friends thanksReview on precious wrist watches
    Last edited by Curt; Jun 3rd, 2010 at 01:07 AM.

  9. #9
    Join Date
    Mar 2010
    Location
    Minneapolis, MN
    Posts
    12

    Default

    I am wondering the reasons for using JobRegistrar? Is it for a "production run" configuration need or other?

    Particularly, we're struggling with Spring test contexts with adding a JTA manager (it is loading multiple times - by each test, which is not allowed of course) and it seems the only way to solve it is to load all jobs into JobRegistrar with a top-level @ContextConfiguration for all tests. But revamping to use it is taking time, we're not sure if we are on the correct path, and we have the same concern as you with loading all the jobs to run just one (for prod and tests). I'm still looking into how to arrange the config files for tests and prod run. If you have advice/examples/RTFM, would really appreciate it! This is my post attempting to ask about this.

  10. #10
    Join Date
    Jun 2005
    Posts
    4,230

    Default

    For integration testing I usually don't bother with the AutomaticJobRegistrar (just import the config files needed to get the job to test), but then I don't have to deal with JTA very often. You might need to use @DirtiesContext if you are having trouble with global application contexts interfering with each other in a test suite (hopefully whatever is causing your problem cleans itself up if the context is closed).

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •