Distribute a Spring Batch job on the Proactive Scheduler

25 May 2009 by esalagea

partitionning_scheduler1

As its name states, this article describes the steps to perform in order to have the execution of Spring Batch job processed remotely on an infrastructure managed by the ProActive Scheduling platform.
The solution presented is based on Spring Batch Partitioning; you should take a look at section 7.4. Partitioning in the Spring Batch Documentation.

Here’s the schema from the spring batch documentation:

Spring BatchPartitioning Overview
Spring BatchPartitioning Overview
If you have not already done it, you should download spring batch from http://www.springsource.org/download and ProActive Scheduling from http://www.activeeon.com (you should download the Scheduling Project and eclipse RCPs (the Graphical clients).
This article is based on spring batch 2.0.0 Release and the Scheduling 1.1 release.

Part 1 – Implementation

Start Point

The job I have used for this purpose, as a start point, is the job defined in
org.springframework.batch-2.0.0.RELEASE/sources/org.springframework.batch.core/ src/test/resources/org/springframework/batch/core/partition/launch-context.xml

This spring-batch example job is composed by:

  • simple hello world ItemReader and ItemWriter
    (org.springframework.batch.core.partition.ExampleItemReader
    and org.springframework.batch.core.partition.ExampleItemWriter)
  • a Simple Job implementation (org.springframework.batch.core.job.SimpleJob)
  • a partition step (org.springframework.batch.core.partition.support.PartitionStep) – this is used as implementation for the master step
  • a step execution splitter, used by the partition step (org.springframework.batch.core.partition.support.SimpleStepExecutionSplitter)
  • A PartitionHandler, also used by the Partition Step (org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler)

Bellow, the xml file which defines this job, taken from

org.springframework.batch-2.0.0.RELEASE/sources/org.springframework.batch.core/ src/test/resources/org/springframework/batch/core/partition/launch-context.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd">
<import resource="classpath:/org/springframework/batch/core/repository/dao/data-source-context.xml" />
<bean id="job1" parent="simpleJob">
<property name="steps">
<bean name="step1:master">
<property name="partitionHandler">
<bean>
<property name="taskExecutor">
<bean />
</property>
<property name="step" ref="step1" />
<property name="gridSize" value="2" />
</bean>
</property>
<property name="stepExecutionSplitter">
<bean>
<constructor-arg ref="jobRepository" />
<constructor-arg ref="step1" />
</bean>
</property>
<property name="jobRepository" ref="jobRepository" />
</bean>
</property>
</bean>
<bean id="step1" parent="simpleStep">
<property name="itemReader">
<bean scope="step"></bean>
</property>
<property name="itemWriter">
<bean />
</property>
</bean>
<bean id="simpleJob" abstract="true">
<property name="jobRepository" ref="jobRepository" />
<property name="restartable" value="true" />
</bean>
<bean id="simpleStep" abstract="true">
<property name="transactionManager" ref="transactionManager" />
<property name="jobRepository" ref="jobRepository" />
<property name="startLimit" value="100" />
<property name="commitInterval" value="1" />
</bean>
<bean id="jobLauncher">
<property name="jobRepository" ref="jobRepository" />
</bean>
<bean id="jobRepository" p:databaseType="hsql" p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager" />
<bean />
</beans>

Modify the example partition job to distribute it on the ProActive Scheduler

The ProActive Scheduler offers a java API in order to allow users to create, submit jobs on the scheduler and gather the results. See full documentation and tutorial at http://proactive.inria.fr/release-doc/scheduler/multiple_html/index.html

In order to run a job on the Proactive Scheduler we have to create a specific PartitionHandler.
I’ll call this class ProactiveSchedulerPartitionHandler.

In odrer to implement this class, I took the org.springframework.batch.core.partition.support.TaskExecutorPartitionHandler implementation, changed the handle method and add some properties.
Let’s take a look at the handle method which creates a ProActive Scheduler job, iterates over the step executions returned by the Stpet Execution Splitter and creates a ProActive Scheduling task for each step execution. The created job encapsulates these tasks. The Scheduler will execute them remotely on the available resources.
Bellow, the code of the handle method:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
public Collection handle(
            StepExecutionSplitter stepExecutionSplitter,
            StepExecution masterStepExecution) throws Exception {
 
        Collection result = new ArrayList();
 
        // A job to be scheduled on the ProactiveScheduler
        TaskFlowJob proactiveSchedulerJob = new TaskFlowJob();
        proactiveSchedulerJob.setName("Master Step: "
                + masterStepExecution.toString());
 
        // the step executions
        Set stepExecutions = stepExecutionSplitter.split(
                masterStepExecution, gridSize);
 
        for (StepExecution stepExecution : stepExecutions) {
            String jobExecutionId = stepExecution.getJobExecution().getId()
                    .toString();
            String stepExecutionId = stepExecution.getId().toString();
            String stepName = step.getName();
 
            JavaTask jt = new JavaTask();
            jt.setName(stepExecutionId);
            jt.setExecutableClassName(StepExecutable.class.getName());
            jt.addArgument(StepExecutable.JOB_EXECUTION_ID, jobExecutionId);
            jt.addArgument(StepExecutable.STEP_EXECUTION_ID, stepExecutionId);
            jt.addArgument(StepExecutable.STEP_NAME, stepName);
            jt.addArgument(StepExecutable.JOB_CONFIG_FILE,
                    "/launch-context.xml");
            proactiveSchedulerJob.addTask(jt);
 
        }// for all StepExecution
 
        this.setJobClasPath(proactiveSchedulerJob);
 
        SchedulerAuthenticationInterface auth = SchedulerConnection
                .join(proactiveSchedulerUrl);
        UserSchedulerInterface uischeduler = auth.logAsUser(
                proactiveSchedulerUserName, proactiveSchedulerPassword);
        JobId id = uischeduler.submit(proactiveSchedulerJob);
 
        // blocking loop until we have the result:
 
        JobResult jr = null;
        while (jr == null) {
            Thread.sleep(3000);
            jr = uischeduler.getJobResult(id);
 
        }
 
        Map jobResults = jr.getAllResults();
        // the jobresults map contains entries of type:
        // and the task_name is the same as the corresponding step execution id
        // Therefore we iterate over the stepExecutions list and get the result
        // for each stepExecution
        // This will allow us to manage exceptions on the remote tasks
 
        for (StepExecution stepExecution : stepExecutions) {
            TaskResult taskResult = jobResults.get(stepExecution.getId()
                    .toString());
            try {
                StepExecution se = (StepExecution) taskResult.value();
                result.add(se);
            } catch (Throwable t) {
                // an exception has been thrown during the launch of the task on
                // the remote node
                // we will mark the local step execution as FAILED, attach the
                // exception to it and addd it to the results
 
                ExitStatus exitStatus = ExitStatus.FAILED
                        .addExitDescription("TaskExecutor rejected the task for this step.");
                stepExecution.setStatus(BatchStatus.FAILED);
                stepExecution.setExitStatus(exitStatus);
                stepExecution.addFailureException(t);
                result.add(stepExecution);
 
                // we print the stacktrace:
                System.out.println("an error occured while executing the step "
                        + stepExecution.getId().toString() + ":");
                t.printStackTrace();
 
            }
        }
        return result;
    }

First we create a TaskFlowJob (a job containing a set of tasks that may have dependencies between them).
This job will be sent to the Scheduler for distributed execution.
Then we obtain a list of step execution from the stepExecutionSplitter. We iterate over this list and, for each step execution, we create a task for our job. The java code for the task is defined by the StepExecutable class. Each task will receive in argument the job execution id, the step execution id and the initial job configuration file so the respective step execution could be retrieved from an application context on the remote node.
Next thing to notice is the job classpath: we add to our job a job environment containing the classes of our application so they could be found on the remote node.
Finally we connect to the Scheduler, send the job and wait for the results.
See the full code of the class below:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
package com.activeeon.sandbox.spring;
 
import java.io.File;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
 
import org.ow2.proactive.scheduler.common.SchedulerAuthenticationInterface;
import org.ow2.proactive.scheduler.common.SchedulerConnection;
import org.ow2.proactive.scheduler.common.UserSchedulerInterface;
import org.ow2.proactive.scheduler.common.job.JobEnvironment;
import org.ow2.proactive.scheduler.common.job.JobId;
import org.ow2.proactive.scheduler.common.job.JobResult;
import org.ow2.proactive.scheduler.common.job.TaskFlowJob;
import org.ow2.proactive.scheduler.common.task.JavaTask;
import org.ow2.proactive.scheduler.common.task.TaskResult;
import org.springframework.batch.core.BatchStatus;
import org.springframework.batch.core.ExitStatus;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.partition.PartitionHandler;
import org.springframework.batch.core.partition.StepExecutionSplitter;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.util.Assert;
 
/**
 * A {@link PartitionHandler} that creates and submit a job on the ProActive
 * Scheduler
 *
 * @author Emil Salageanu
 *
 */
public class ProactiveSchedulerPartitionHandler implements PartitionHandler,
        InitializingBean {
 
    private int gridSize = 1;
 
    private String proactiveSchedulerUrl;
    private String proactiveSchedulerUserName;
    private String proactiveSchedulerPassword;
 
    private Step step;
 
    public void afterPropertiesSet() throws Exception {
        Assert.notNull(step, "A Step must be provided.");
    }
 
    /**
     * Passed to the {@link StepExecutionSplitter} in the
     * {@link #handle(StepExecutionSplitter, StepExecution)} method, instructing
     * it how many {@link StepExecution} instances are required, ideally. The
     * {@link StepExecutionSplitter} is allowed to ignore the grid size in the
     * case of a restart, since the input data partitions must be preserved.
     *
     * @param gridSize
     *            the number of step executions that will be created
     */
    public void setGridSize(int gridSize) {
        this.gridSize = gridSize;
    }
 
    /**
     * Setter for the {@link Step} that will be used to execute the partitioned
     * {@link StepExecution}. This is a regular Spring Batch step, with all the
     * business logic required to complete an execution based on the input
     * parameters in its {@link StepExecution} context.
     *
     * @param step
     *            the {@link Step} instance to use to execute business logic
     */
    public void setStep(Step step) {
        this.step = step;
    }
 
    /**
     * @see PartitionHandler#handle(StepExecutionSplitter, StepExecution)
     */
    public Collection handle(
            StepExecutionSplitter stepExecutionSplitter,
            StepExecution masterStepExecution) throws Exception {
 
        Collection result = new ArrayList();
 
        // A job to be scheduled on the ProactiveScheduler
        TaskFlowJob proactiveSchedulerJob = new TaskFlowJob();
        proactiveSchedulerJob.setName("Master Step: "
                + masterStepExecution.toString());
 
        // the step executions
        Set stepExecutions = stepExecutionSplitter.split(
                masterStepExecution, gridSize);
 
        for (StepExecution stepExecution : stepExecutions) {
            String jobExecutionId = stepExecution.getJobExecution().getId()
                    .toString();
            String stepExecutionId = stepExecution.getId().toString();
            String stepName = step.getName();
 
            JavaTask jt = new JavaTask();
            jt.setName(stepExecutionId);
            jt.setExecutableClassName(StepExecutable.class.getName());
            jt.addArgument(StepExecutable.JOB_EXECUTION_ID, jobExecutionId);
            jt.addArgument(StepExecutable.STEP_EXECUTION_ID, stepExecutionId);
            jt.addArgument(StepExecutable.STEP_NAME, stepName);
            jt.addArgument(StepExecutable.JOB_CONFIG_FILE,
                    "/launch-context.xml");
            proactiveSchedulerJob.addTask(jt);
 
        }// for all StepExecution
 
        this.setJobClasPath(proactiveSchedulerJob);
 
        SchedulerAuthenticationInterface auth = SchedulerConnection
                .join(proactiveSchedulerUrl);
        UserSchedulerInterface uischeduler = auth.logAsUser(
                proactiveSchedulerUserName, proactiveSchedulerPassword);
        JobId id = uischeduler.submit(proactiveSchedulerJob);
 
        // blocking loop until we have the result:
 
        JobResult jr = null;
        while (jr == null) {
            Thread.sleep(3000);
            jr = uischeduler.getJobResult(id);
 
        }
 
        Map jobResults = jr.getAllResults();
        // the jobresults map contains entries of type:
        // and the task_name is the same as the corresponding step execution id
        // Therefore we iterate over the stepExecutions list and get the result
        // for each stepExecution
        // This will allow us to manage exceptions on the remote tasks
 
        for (StepExecution stepExecution : stepExecutions) {
            TaskResult taskResult = jobResults.get(stepExecution.getId()
                    .toString());
            try {
                StepExecution se = (StepExecution) taskResult.value();
                result.add(se);
            } catch (Throwable t) {
                // an exception has been thrown during the launch of the task on
                // the remote node
                // we will mark the local step execution as FAILED, attach the
                // exception to it and addd it to the results
 
                ExitStatus exitStatus = ExitStatus.FAILED
                        .addExitDescription("TaskExecutor rejected the task for this step.");
                stepExecution.setStatus(BatchStatus.FAILED);
                stepExecution.setExitStatus(exitStatus);
                stepExecution.addFailureException(t);
                result.add(stepExecution);
 
                // we print the stacktrace:
                System.out.println("an error occured while executing the step "
                        + stepExecution.getId().toString() + ":");
                t.printStackTrace();
 
            }
        }
        return result;
    }
 
    public void setProactiveSchedulerUrl(String proactiveSchedulerUrl) {
        this.proactiveSchedulerUrl = proactiveSchedulerUrl;
    }
 
    public void setProactiveSchedulerUserName(String proactiveSchedulerUserName) {
        this.proactiveSchedulerUserName = proactiveSchedulerUserName;
    }
 
    public void setProactiveSchedulerPassword(String proactiveSchedulerPassword) {
        this.proactiveSchedulerPassword = proactiveSchedulerPassword;
    }
 
    protected void setJobClasPath(org.ow2.proactive.scheduler.common.job.Job job) {
 
        String appClassPath = "";
        try {
            File appMainFolder = new File(this.getClass().getProtectionDomain()
                    .getCodeSource().getLocation().toURI());
            appClassPath = appMainFolder.getAbsolutePath();
        } catch (java.net.URISyntaxException e1) {
            e1.printStackTrace();
        }
        JobEnvironment je = new JobEnvironment();
        try {
            je.setJobClasspath(new String[] { appClassPath });
            System.out.println("job classpath: " + appClassPath);
        } catch (java.io.IOException e) {
            e.printStackTrace();
        }
        job.setEnvironment(je);
    }
 
  }

Note that I have removed the taskExecutor property from the bean (we don’t need a task executroanymore), and added 3 properties for the connection to the Scheduler (scheduler url, username, password).

The second and last class we need to implement is the StepExecutable class which defines the code to be executed on the remote node. It defines an execute method which does nothing more than creating a spring application context, gathering the step execution and executing it. See the code bellow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
package com.activeeon.sandbox.spring;
 
import java.io.Serializable;
import java.util.Map;
 
import org.ow2.proactive.scheduler.common.task.TaskResult;
import org.ow2.proactive.scheduler.common.task.executable.JavaExecutable;
import org.springframework.batch.core.JobInterruptedException;
import org.springframework.batch.core.Step;
import org.springframework.batch.core.StepExecution;
import org.springframework.batch.core.explore.JobExplorer;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
 
public class StepExecutable extends JavaExecutable {
 
    public static final String JOB_EXECUTION_ID = "jobExecutionId";
    public static final String STEP_EXECUTION_ID = "stepExecutionId";
    public static final String STEP_NAME = "stepName";
    public static final String JOB_CONFIG_FILE = "JobConfigFile";
 
    private Long jobExecutionId;
    private Long stepExecutionId;
    private String stepName;
    private String configFile;
 
    @Override
    public void init(Map args) throws Exception {
        jobExecutionId = Long.parseLong(args.get(JOB_EXECUTION_ID));
        stepExecutionId = Long.parseLong(args.get(STEP_EXECUTION_ID));
        stepName = args.get(STEP_NAME);
        configFile = args.get(JOB_CONFIG_FILE);
    }
 
    @Override
    public Serializable execute(TaskResult... arg0) throws Throwable {
 
        ApplicationContext context = new ClassPathXmlApplicationContext(
                configFile, this.getClass());
 
        System.out.println("ApplicationContext ClassLoader:"
                + context.getClass().getClassLoader());
 
        BeanFactory factory = context;
        Step step = (Step) factory.getBean(stepName);
        JobExplorer je = (JobExplorer) factory.getBean("jobExplorer");
        StepExecution stepExecution = (StepExecution) je.getStepExecution(
                jobExecutionId, stepExecutionId);
 
        try {
            step.execute(stepExecution);
        } catch (JobInterruptedException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
            stepExecution.addFailureException(e);
        }
        return stepExecution;
    }
 
}

Part 2 – Configuration and run

Configuration files

The job configuration xml file is the shown bellow:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
<?xml version="1.0" encoding="UTF-8">
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:p="http://www.springframework.org/schema/p" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.xsd"> <import resource="my-data-source-context.xml" />
	<bean id="PAJOB" parent="simpleJob"> <property name="name" value ="myJob44"/>
		<property name="steps">
			<bean name="step1:master">
				<property name="partitionHandler">
					<bean>
						<property name="step" ref="step1" />
						<property name="gridSize" value="2" />
						<property name = "proactiveSchedulerUrl" value = "rmi://192.168.1.10:1099"/>
						<property name = "proactiveSchedulerUserName" value = "admin"/>
						<property name = "proactiveSchedulerPassword" value = "admin"/>
					</bean>
				</property>
				<property name="stepExecutionSplitter">
					<bean>
						<constructor-arg ref="jobRepository" />
						<constructor-arg ref="step1" />
					</bean>
				</property>
				<property name="jobRepository" ref="jobRepository" />
			</bean>
		</property>
	</bean>
	<bean id="step1" parent="simpleStep">
		<property name="itemReader">
			<bean scope="step">
			</bean>
		</property>
		<property name="itemWriter">
			<bean />
		</property>
	</bean>
	<bean id="simpleJob" abstract="false">
		<property name="jobRepository" ref="jobRepository" />
		<property name="restartable" value="true" />
	</bean>
	<bean id="simpleStep" abstract="false">
		<property name="transactionManager" ref="transactionManager" />
		<property name="jobRepository" ref="jobRepository" />
		<property name="startLimit" value="100" />
		<property name="commitInterval" value="1" />
	</bean>
	<bean id="jobLauncher">
		<property name="jobRepository" ref="jobRepository" />
	</bean>
	<bean id="jobRepository" p:databaseType="mysql" p:dataSource-ref="dataSource" p:transactionManager-ref="transactionManager" />
	<bean id="jobExplorer" p:dataSource-ref="dataSource" p:tablePrefix="BATCH_" />
	<bean />
</beans>

I use a mysql database as datasource, defined in the my-data-source-context.xml file, bellow:

1
2
3
4
5
<property name="initScripts">
    <list>
        <value>schema-mysql.sql</value>
    </list>
</property>

Now, we still need two configuration files for the Proactive managed infrastructure … well, you didn’t expect to finish this tutorial in 15 minutes, did you? We’re almost finished …

We will use ProActive Resource Manager in order to deploy a set of remote resources (start remote JVMs and use them to perform computation): A GCMApplication file and a GCMDeployment file.
GCMApplication
By default, the remote jvm’s classpath is defined in the file Scheduler1_0/config/deployment/GCMNodeSourceApplication.xml (we’re talking about the JVMs deployed by the Resource Manager). You should either modify this file or create a new one, in order to add spring jars in the classpath of remote nodes.
My GCMNodeSourceApplication.xml is :

1
2
3
4
5
6
7
8
9
10
11
12
<!-- this variable will be replaced by a path of a GCMD to deploy, by RMAdmin -->
<!-- Commented dependencies are referenced through the Jar-Index of Scheduler jars -->
<!-- Script engines must be explicitly in application classpath -->
<!-- Needed explicitly by VFS (file transfer in pre/post script -->
<!--
<pathElement base="proactive" relpath="/dist/lib/script-api.jar" />
<pathElement base="proactive" relpath="/dist/lib/js.jar" />
<pathElement base="proactive" relpath="/dist/lib/jruby.jar" />
<pathElement base="proactive" relpath="/dist/lib/jython.jar" /> -->
 
<!-- Spring jars  -->
<!-- MySQL JDBC Driver -->

I have added, in this GCMApplication file the spring-batch jars I need, the jar for the java mysql driver and a folder containing my context-xml file accessible on the remote node.

NOTE: We hope that, in the next version of Scheduling, you will not have to specify the folder containing the spring job’s definition xml file – this should be
automatically transfered by proactive.

GCMDeployment

Choose a GCMDeployment file in [Scheduler_Home]/config/deployment and modify it accoring to your infrastructure or just use
[Scheduler_Home]/config/deployment/Local4JVMDeployment.xml to specify that you want 4 jvms deployed on localhost.

Run the Application

Here we are …
First of all, start the Resource Manager and the Scheduler Servers:

Start Resource Manager:
go to [Scheduing_Home]/bin/unix and type

./startRM.sh –deploy [Scheduler_Home]/config/deployment/Local4JVMDeployment.xml

Note: if you have not modified the GCMNodeSourceApplication.xml (to add spinrg jars, remember?) but created a different file, you have to modify the startRM.sh file and add this option to the JAVACMD:

  -Dpa.rm.gcm.template.application.file=path/to/my/GCMNodeSourceApplication.xml

Note: you can also start the RM without the deploy option and deploy later from the RM User Interface.
Start the Scheduler:

go to [Scheduing_Home]/bin/unix and type:

  ./startScheduler_newDB.sh

Now you can start the Graphical User Interfaces (RCP’s) for the Resource Manager and the Scheduler and connect them to the respective servers.

And finally, start your application.
You can use org.springframework.batch.core.launch.support.CommandLineJobRunner with arguments launch-context.xml PAJOB (do not forget to add spring jars for your application).
You can download source and configuration files here SpringBatchAndSchedulerSRC

Hope it works, if it doesn’t, leave a message.





No Comments »

No comments yet.

RSS feed for comments on this post. TrackBack URL

Leave a comment

IMPORTANT! To be able to proceed, you need to solve the following simple math (so we know that you are a human) :-)

What is 9 + 11 ?
Please leave these two fields as-is:
© 2010 ACTIVEEON S.A.S. All right reserved - Online Privacy Policy