├── .gitignore
├── LICENSE
├── README.md
└── spring-batch-quartz-example
├── pom.xml
└── src
└── main
├── java
└── org
│ └── sbq
│ └── batch
│ ├── configurations
│ ├── ActivityEmulatorConfiguration.java
│ ├── DatabaseConfiguration.java
│ ├── SchedulerRunnerConfiguration.java
│ └── SpringBatchConfiguration.java
│ ├── dao
│ ├── UserActionDao.java
│ ├── UserDao.java
│ ├── UserSessionDao.java
│ └── impl
│ │ ├── UserActionDaoImpl.java
│ │ ├── UserDaoImpl.java
│ │ └── UserSessionDaoImpl.java
│ ├── domain
│ ├── User.java
│ ├── UserAction.java
│ └── UserSession.java
│ ├── exceptions
│ └── TransientException.java
│ ├── mains
│ ├── ActivityEmulator.java
│ └── SchedulerRunner.java
│ ├── scheduled
│ ├── AbstractScheduledJob.java
│ ├── CalculateEventMetricsScheduledJob.java
│ ├── CalculateOnlineMetricsScheduledJob.java
│ └── LongRunningBatchScheduledJob.java
│ ├── scheduler
│ └── QuartzSchedulerFactory.java
│ ├── service
│ ├── MetricsService.java
│ ├── UserService.java
│ └── impl
│ │ ├── MetricsServiceImpl.java
│ │ └── UserServiceImpl.java
│ └── tasks
│ ├── CalculateEventMetricsTask.java
│ ├── CalculateOnlineMetricsTask.java
│ └── LongRunningBatchTask.java
└── resources
├── init.sql
├── log4j.xml
├── quartz.properties
└── spring-batch-conf.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | # Igore instructions for Git #
2 | ##############################
3 |
4 | # Maven files
5 | */target/**
6 |
7 | # IDE files
8 | .idea/**
9 | *.iml
10 | atlassian-ide-plugin.xml
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Copyright (C) 2013 Ilya Sorokoumov
2 |
3 | Licensed under the Apache License, Version 2.0 (the "License");
4 | you may not use this file except in compliance with the License.
5 | You may obtain a copy of the License at
6 |
7 | http://www.apache.org/licenses/LICENSE-2.0
8 |
9 | Unless required by applicable law or agreed to in writing, software
10 | distributed under the License is distributed on an "AS IS" BASIS,
11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 | See the License for the specific language governing permissions and
13 | limitations under the License.
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | spring-batch-quartz-example
2 | ===========================
3 |
4 | ## Summary ##
5 |
6 | An example which is meant to show how Spring Batch and Quartz can address the key issues of batch processing and job scheduling in a clustered
7 | environment.
8 |
9 | ## Used Technologies ##
10 |
11 | Spring Framework(IoC, JDBC, Transactions, etc.), Quartz Scheduler, Spring Batch, MySQL.
12 |
13 | ## Project details ##
14 |
15 | ### How to run ###
16 |
17 | The application contains two "main" classes:
18 |
19 | 1) org.sbq.batch.mains.ActivityEmulator does exactly what it's supposed to, it emulates some activity from users. This part is only needed to
20 | keep adding some new data to DB. You should run only one instance of this class(meaning that this part does not deal with clustering).
21 |
22 | 2) org.sbq.batch.mains.SchedulerRunner is meant to be run in multiple instances concurrently in order to simulate a bunch of nodes in a cluster.
23 |
24 | ### Simulated environment ###
25 |
26 | The example is meant to test the following environment: several servers(at least 2 nodes) running in a cluster against RDBMS(hopefully clustered)
27 | which have to perform certain batch tasks periodically and have fail-over, work distribution etc.
28 |
29 | ### Implemented Jobs ###
30 |
31 | CalculateEventMetricsScheduledJob: calculates a number of occurrences for each type of event since last job run and updates the site
32 | statistic entry(which hold metrics of site since its start); Triggered each 5 minutes; saves where it finished(time for which it processed);
33 | misfire policy 'FireOnceAndProceed', meaning that only one call to the job is needed for any number of misfires;
34 |
35 | CalculateOnlineMetricsScheduledJob: calculates total number of users online, number of users jogging, chatting,
36 | dancing and idle for a certain point of time; Triggered each 15 seconds;
37 | uses ScheduledFireTime from Quartz to identify for which point it should calculate the metrics; misfire policy 'IgnoreMisfire',
38 | meaning that all missed executions will be fired as soon as Quartz identifies them(so that the job can catch up);
39 | this job randomly (in ~ 1/3 of cases) throws an exception(TransientException) in order to emulate network issues;
40 |
41 | ## Addressed Scenarios ##
42 |
43 | ### Scheduler: No single point of failure ###
44 |
45 | Use case: Make sure that if one node goes down, the scheduled tasks are still being executed by the rest of the nodes.
46 |
47 | How supported/implemented: Quartz should be running on each machine in a cluster.
48 | Each Quartz should be configured to work with DB-backed JobStore and clustering should be enabled in Quartz properties.
49 | When at least 1 node with Quartz is up, the scheduled tasks will keep being executed(guaranteed by Quartz architecture).
50 |
51 | Steps to verify: Run init.sql. Start one instance of ActivityEmulator(optional). Start several instances of SchedulerRunner.
52 | Watch them executing jobs. Kill some of them. See how load is spread between the nodes which are left running.
53 |
54 | ### Scheduler: Work distribution ###
55 |
56 | Use case: Make sure that the tasks are getting distributed among nodes in the cluster.
57 | (This is important because after a certain point one node won't be able to handle all tasks).
58 |
59 | How supported/implemented: Quartz with DB JobStore performs work distribution automatically.
60 |
61 | Steps to verify: Run init.sql. Start one instance of ActivityEmulator(optional). Start several instances of SchedulerRunner.
62 | Looking at the log file on each instance of SchedulerRunner verify that the tasks are executed on each node(The distribution is not guaranteed to
63 | be even).
64 |
65 | ### Scheduler: Misfire Support ###
66 |
67 | Use case: Make sure that if all nodes go down and then after while at least one is back online,
68 | all of missed job executions(for particular jobs which are sensitive to misfires) are invoked.
69 |
70 | How supported/implemented: Quartz with DB JobStore performs detection of misfired jobs automatically upon startup of the first node from
71 | cluster.
72 |
73 | Steps to verify: Run init.sql. Start one instance of ActivityEmulator(optional).
74 | Start several instances of SchedulerRunner. Stop all instances of SchedulerRunner. Wait for some time.
75 | Start at least one instance of SchedulerRunner. See how misfired executions are detected and executed.
76 |
77 | ### Scheduler: Task Recovery ###
78 |
79 | Use case: Make sure that if a node executing a certain job goes down, the job is automatically repeated/re-started.
80 |
81 | How supported/implemented: This use case is tricky because a server crash is likely to leave the job in unknown state(especially if it
82 | writes data into non-transactional storage like Mongo). For now I assume the simplest use-case where the job just have to be restarted and we can
83 | ignore the fact of possible data collisions. Using requestRecovery feature from Quartz and SYNCHRONOUS executor(which uses Quartz thread for
84 | performing batch processing) we can rely on Quartz in terms of identifying crashed jobs and re-invoking them on a different node(or on the same one
85 | if it's up and the first one to identify the problem).
86 |
87 | NOTE: I think that a more smooth transition for job recovery can be made by storing job state in ExecutionContext which will be picked up by
88 | Spring Batch when you create a new execution for the same job instance.
89 |
90 | Steps to verify: Run init.sql. Start one instance of ActivityEmulator(optional). Start several instances of SchedulerRunner.
91 | Look at the logs and find out which SchedulerRunner is running LongRunningBatchScheduledJob, kill it. See how after a while another job logs the
92 | message that it's picked up the job(it can also be verified in DB by looking at executions table).
93 |
94 | ### Spring Batch: Retries Support ###
95 |
96 | Use case: Retry a job if it fails due to a transient problem(such as a network connectivity issue, or DB being down for a couple of minutes).
97 |
98 | How supported/implemented: Spring Batch provides RetryTemplate and RetryOperationsInterceptor for this purpose,
99 | which allow to specify number of retries, back-off policy and types of exceptions which considered retry-able.
100 |
101 | Steps to verify: Run init.sql. Start one instance of ActivityEmulator(optional). Start several instances of SchedulerRunner.
102 | In logs you should see "calculateOnlineMetrics() - TRANSIENT EXCEPTION..." which indicates that exception has been thrown but a method of Service
103 | class was retried by RetryOperationsInterceptor.
104 |
105 | ### General: Monitoring ###
106 |
107 | Use case: There should be an easy way to get the following info at any point in time:
108 | list of all jobs which are being executed at the moment, history of all job executions(with parameters and execution results success/failure),
109 | list of all scheduled jobs(e.g. next time a particular job runs etc.).
110 |
111 | How supported/implemented: In fact all this information can be obtained from Quartz and Spring Batch abstractions in java code. For some
112 | cases you can look into DB and find out the status of running jobs, history etc. There is also Spring Batch Admin web-app which can be used for
113 | this purpose.
114 |
115 | Steps to verify: see 'How supported/implemented' section.
116 |
117 | ## Un-Addressed Scenarios ##
118 |
119 | ### General: Execution Management ###
120 |
121 | Q: How do I manually re-execute a particular job(with given parameters) if it fails completely(i.e. no luck after N auto-retries)?
122 |
123 | A: Not implemented at the moment. In fact we should consider using JMS in order to deliver a command to a cluster of batch processing nodes.
124 | Then a JMS listener will trigger a specified Spring Batch job.
125 |
126 | ### General: Graceful Halt ###
127 |
128 | Q: How can I signal to all nodes to stop, so that I can deploy a new version of software, do maintenance etc.?
129 |
130 | A: I think this is also should be done via JMS message(send to a topic!). Upon receiving of a message each node should: a) stop Quartz b)
131 | wait for all nodes which don't support re-start c) stop all nodes which support re-start (the jobs which can save the point where they left and
132 | resume from that point). Also see http://numberformat.wordpress.com/tag/batch/ for some info on graceful stop.
--------------------------------------------------------------------------------
/spring-batch-quartz-example/pom.xml:
--------------------------------------------------------------------------------
1 |
2 |
5 | 4.0.0
6 | org.ilya40umov.batch
7 | spring-batch-quartz-example
8 | 1.0.0-SNAPSHOT
9 | jar
10 | Example of Spring Batch With Quartz
11 |
12 |
13 | UTF-8
14 | 1.6
15 |
16 | 2.1.9.RELEASE
17 | 3.1.2.RELEASE
18 | 1.6.1
19 | 1.2.17
20 | 6.3
21 | 1.9.0
22 | 2.2.2
23 | 12.0
24 | 2.1.6
25 | 2.1
26 |
27 | 2.12
28 | 2.3.2
29 |
30 |
31 |
32 |
33 | org.quartz-scheduler
34 | quartz
35 | ${org.quartz.version}
36 |
37 |
38 | joda-time
39 | joda-time
40 | ${joda.time.version}
41 |
42 |
43 | com.google.guava
44 | guava
45 | ${guava.version}
46 |
47 |
48 | org.mockito
49 | mockito-core
50 | ${mockito.core.version}
51 | test
52 |
53 |
54 | org.springframework
55 | spring-context
56 | ${org.springframework.version}
57 | compile
58 |
59 |
60 | org.springframework
61 | spring-core
62 | ${org.springframework.version}
63 | compile
64 |
65 |
66 | org.springframework
67 | spring-context-support
68 | ${org.springframework.version}
69 | compile
70 |
71 |
72 | aopalliance
73 | aopalliance
74 | 1.0
75 |
76 |
77 |
78 | org.aspectj
79 | aspectjrt
80 | 1.6.12
81 |
82 |
83 | org.aspectj
84 | aspectjweaver
85 | 1.6.12
86 |
87 |
88 | org.springframework
89 | spring-aop
90 | ${org.springframework.version}
91 | compile
92 |
93 |
94 | org.springframework
95 | spring-tx
96 | ${org.springframework.version}
97 | compile
98 |
99 |
100 | org.springframework
101 | spring-jdbc
102 | ${org.springframework.version}
103 | compile
104 |
105 |
106 | org.springframework
107 | spring-test
108 | ${org.springframework.version}
109 | test
110 |
111 |
112 | cglib
113 | cglib
114 | ${cglib.version}
115 |
116 |
117 | org.slf4j
118 | slf4j-api
119 | ${org.slf4j.version}
120 |
121 |
122 | org.slf4j
123 | jcl-over-slf4j
124 | ${org.slf4j.version}
125 |
126 |
127 | org.slf4j
128 | slf4j-log4j12
129 | runtime
130 | ${org.slf4j.version}
131 |
132 |
133 | log4j
134 | log4j
135 | runtime
136 | ${log4j.version}
137 |
138 |
139 |
140 | mysql
141 | mysql-connector-java
142 | 5.1.22
143 |
144 |
145 |
146 | commons-dbcp
147 | commons-dbcp
148 | 1.4
149 |
150 |
151 |
152 |
153 | org.springframework.batch
154 | spring-batch-core
155 | ${spring.batch.version}
156 |
157 |
158 | org.springframework.batch
159 | spring-batch-infrastructure
160 | ${spring.batch.version}
161 |
162 |
163 |
164 | org.springframework.batch
165 | spring-batch-test
166 | ${spring.batch.version}
167 | test
168 |
169 |
170 |
171 | org.testng
172 | testng
173 | ${testng.version}
174 | test
175 |
176 |
177 | junit
178 | junit
179 |
180 |
181 |
182 |
183 |
184 |
185 |
186 | org.apache.maven.plugins
187 | maven-surefire-plugin
188 | ${surefire.plugin.version}
189 |
190 |
191 | ${project.build.testOutputDirectory}
192 |
193 |
194 |
195 |
196 | true
197 | org.apache.maven.plugins
198 | maven-compiler-plugin
199 | ${compiler.plugin.version}
200 |
201 | ${java.version}
202 | ${java.version}
203 | true
204 | true
205 | UTF-8
206 |
207 |
208 |
209 |
210 |
211 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/configurations/ActivityEmulatorConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.configurations;
17 |
18 | import org.springframework.context.annotation.ComponentScan;
19 | import org.springframework.context.annotation.Configuration;
20 | import org.springframework.context.annotation.Import;
21 |
22 | /**
23 | * @author ilya40umov
24 | */
25 | @Configuration
26 | @ComponentScan({"org.sbq.batch.service", "org.sbq.batch.dao"})
27 | @Import(DatabaseConfiguration.class)
28 | public class ActivityEmulatorConfiguration
29 | {
30 | }
31 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/configurations/DatabaseConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.configurations;
17 |
18 | import org.apache.commons.dbcp.BasicDataSource;
19 | import org.springframework.context.annotation.Bean;
20 | import org.springframework.context.annotation.Configuration;
21 | import org.springframework.context.annotation.Primary;
22 | import org.springframework.jdbc.core.JdbcTemplate;
23 | import org.springframework.jdbc.datasource.DataSourceTransactionManager;
24 | import org.springframework.jdbc.datasource.LazyConnectionDataSourceProxy;
25 | import org.springframework.transaction.PlatformTransactionManager;
26 | import org.springframework.transaction.annotation.EnableTransactionManagement;
27 |
28 | import javax.sql.DataSource;
29 | import java.sql.Connection;
30 |
31 | /**
32 | * @author ilya40umov
33 | */
34 | @Configuration
35 | @EnableTransactionManagement
36 | public class DatabaseConfiguration
37 | {
38 | @Bean
39 | public PlatformTransactionManager transactionManager()
40 | {
41 | return new DataSourceTransactionManager(dataSource());
42 | }
43 |
44 | @Bean
45 | @Primary
46 | public DataSource dataSource()
47 | {
48 | return new LazyConnectionDataSourceProxy(dbcpDataSource());
49 | }
50 |
51 | @Bean(destroyMethod = "close")
52 | public DataSource dbcpDataSource()
53 | {
54 | BasicDataSource dataSource = new BasicDataSource();
55 | dataSource.setDriverClassName("com.mysql.jdbc.Driver");
56 | dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/batch_db");
57 | dataSource.setUsername("root");
58 | dataSource.setPassword("wakeup");
59 | dataSource.setMaxActive(20);
60 | dataSource.setMaxIdle(20);
61 | dataSource.setMaxWait(10000);
62 | dataSource.setInitialSize(5);
63 | dataSource.setValidationQuery("SELECT 1");
64 | dataSource.setDefaultTransactionIsolation(Connection.TRANSACTION_READ_COMMITTED);
65 | return dataSource;
66 | }
67 |
68 | @Bean
69 | public JdbcTemplate jdbcTemplate()
70 | {
71 | return new JdbcTemplate(dataSource());
72 | }
73 | }
74 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/configurations/SchedulerRunnerConfiguration.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.configurations;
17 |
18 | import org.springframework.context.annotation.ComponentScan;
19 | import org.springframework.context.annotation.Configuration;
20 | import org.springframework.context.annotation.Import;
21 |
22 | /**
23 | * @author ilya40umov
24 | */
25 | @Configuration
26 | @Import({DatabaseConfiguration.class, SpringBatchConfiguration.class})
27 | @ComponentScan({"org.sbq.batch.scheduler", "org.sbq.batch.service", "org.sbq.batch.dao"})
28 | public class SchedulerRunnerConfiguration
29 | {
30 |
31 | }
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/configurations/SpringBatchConfiguration.java:
--------------------------------------------------------------------------------
1 | package org.sbq.batch.configurations;
2 |
3 | import org.springframework.context.annotation.Configuration;
4 | import org.springframework.context.annotation.ImportResource;
5 |
6 | /**
7 | * @author ilya40umov
8 | */
9 | @Configuration
10 | @ImportResource("classpath:spring-batch-conf.xml")
11 | public class SpringBatchConfiguration
12 | {
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/dao/UserActionDao.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.dao;
17 |
18 | import org.sbq.batch.domain.UserAction;
19 |
20 | /**
21 | * @author ilya40umov
22 | */
23 | public interface UserActionDao
24 | {
25 | void insert(UserAction userAction);
26 |
27 | }
28 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/dao/UserDao.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.dao;
17 |
18 | import org.sbq.batch.domain.User;
19 |
20 | import java.util.List;
21 |
22 | /**
23 | * @author ilya40umov
24 | */
25 | public interface UserDao
26 | {
27 | List findAllUsers();
28 |
29 | User findUserByLogin(String login);
30 | }
31 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/dao/UserSessionDao.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.dao;
17 |
18 | import org.sbq.batch.domain.UserSession;
19 |
20 | import java.util.Date;
21 |
22 | /**
23 | * @author ilya40umov
24 | */
25 | public interface UserSessionDao
26 | {
27 |
28 | void insert(UserSession userSession);
29 |
30 | UserSession findUserSessionBySessionId(String sessionId);
31 |
32 | void updateEndTime(String sessionId, Date endTime);
33 |
34 | }
35 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/dao/impl/UserActionDaoImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.dao.impl;
17 |
18 | import org.sbq.batch.dao.UserActionDao;
19 | import org.sbq.batch.domain.UserAction;
20 | import org.springframework.beans.factory.annotation.Autowired;
21 | import org.springframework.jdbc.core.JdbcTemplate;
22 | import org.springframework.stereotype.Repository;
23 | import org.springframework.transaction.annotation.Transactional;
24 |
25 | /**
26 | * @author ilya40umov
27 | */
28 | @Repository
29 | @Transactional
30 | public class UserActionDaoImpl implements UserActionDao
31 | {
32 | @Autowired
33 | private JdbcTemplate jdbcTemplate;
34 |
35 | @Override
36 | public void insert(UserAction userAction)
37 | {
38 | String sql = "INSERT INTO SBQ_USER_ACTION (USER_SESSION_ID, ACTION, CREATED) VALUES (?, ?, NOW())";
39 | jdbcTemplate.update(sql, new Object[]{userAction.getUserSessionId(), userAction.getAction().toString()});
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/dao/impl/UserDaoImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.dao.impl;
17 |
18 | import org.sbq.batch.dao.UserDao;
19 | import org.sbq.batch.domain.User;
20 | import org.springframework.beans.factory.annotation.Autowired;
21 | import org.springframework.jdbc.core.JdbcTemplate;
22 | import org.springframework.jdbc.core.RowMapper;
23 | import org.springframework.stereotype.Repository;
24 | import org.springframework.transaction.annotation.Transactional;
25 |
26 | import java.sql.ResultSet;
27 | import java.sql.SQLException;
28 | import java.util.List;
29 |
30 | /**
31 | * @author ilya40umov
32 | */
33 | @Repository
34 | @Transactional
35 | public class UserDaoImpl implements UserDao
36 | {
37 | @Autowired
38 | private JdbcTemplate jdbcTemplate;
39 |
40 | @Override
41 | public List findAllUsers()
42 | {
43 | return jdbcTemplate.query("SELECT * FROM SBQ_USER", new UserRowMapper());
44 | }
45 |
46 | @Override
47 | public User findUserByLogin(String login)
48 | {
49 | return jdbcTemplate.queryForObject("SELECT * FROM SBQ_USER WHERE LOGIN = ?", new UserRowMapper(), login);
50 | }
51 |
52 | public class UserRowMapper implements RowMapper
53 | {
54 | public User mapRow(ResultSet rs, int rowNum) throws SQLException
55 | {
56 | User user = new User();
57 | user.setUserId(rs.getInt("USER_ID"));
58 | user.setLogin(rs.getString("LOGIN"));
59 | user.setCreated(rs.getDate("CREATED"));
60 | return user;
61 | }
62 | }
63 |
64 | }
65 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/dao/impl/UserSessionDaoImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.dao.impl;
17 |
18 | import org.sbq.batch.dao.UserSessionDao;
19 | import org.sbq.batch.domain.UserSession;
20 | import org.springframework.beans.factory.annotation.Autowired;
21 | import org.springframework.jdbc.core.JdbcTemplate;
22 | import org.springframework.jdbc.core.RowMapper;
23 | import org.springframework.stereotype.Repository;
24 | import org.springframework.transaction.annotation.Transactional;
25 |
26 | import java.sql.ResultSet;
27 | import java.sql.SQLException;
28 | import java.util.Date;
29 |
30 | /**
31 | * @author ilya40umov
32 | */
33 | @Repository
34 | @Transactional
35 | public class UserSessionDaoImpl implements UserSessionDao
36 | {
37 | @Autowired
38 | private JdbcTemplate jdbcTemplate;
39 |
40 | @Override
41 | public void insert(UserSession userSession)
42 | {
43 | String sql = "INSERT INTO SBQ_USER_SESSION (USER_ID, SESSION_ID, START_TIME) VALUES (?, ?, ?)";
44 | jdbcTemplate.update(sql, new Object[]{userSession.getUserId(), userSession.getSessionId(),
45 | new java.sql.Date(userSession.getStartTime().getTime())
46 | });
47 | }
48 |
49 | @Override
50 | public UserSession findUserSessionBySessionId(String sessionId)
51 | {
52 | return jdbcTemplate.queryForObject("SELECT * FROM SBQ_USER_SESSION WHERE SESSION_ID = ?", new UserSessionRowMapper(), sessionId);
53 | }
54 |
55 | @Override
56 | public void updateEndTime(String sessionId, Date endTime)
57 | {
58 | String sql = "UPDATE SBQ_USER_SESSION SET END_TIME = ? WHERE SESSION_ID = ?";
59 | jdbcTemplate.update(sql, new Object[]{endTime, sessionId});
60 | }
61 |
62 | public class UserSessionRowMapper implements RowMapper
63 | {
64 | public UserSession mapRow(ResultSet rs, int rowNum) throws SQLException
65 | {
66 | UserSession userSession = new UserSession();
67 | userSession.setUserSessionId(rs.getInt("USER_SESSION_ID"));
68 | userSession.setUserId(rs.getInt("USER_ID"));
69 | userSession.setSessionId(rs.getString("SESSION_ID"));
70 | userSession.setStartTime(rs.getDate("START_TIME"));
71 | userSession.setEndTime(rs.getDate("END_TIME"));
72 | return userSession;
73 | }
74 | }
75 | }
76 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/domain/User.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.domain;
17 |
18 | import java.util.Date;
19 |
20 | /**
21 | * @author ilya40umov
22 | */
23 | public class User
24 | {
25 | private Integer userId;
26 | private String login;
27 | private Date created;
28 |
29 | public User()
30 | {
31 |
32 | }
33 |
34 | public User(String login, Date created)
35 | {
36 | this.login = login;
37 | this.created = created;
38 | }
39 |
40 | public Integer getUserId()
41 | {
42 | return userId;
43 | }
44 |
45 | public void setUserId(Integer userId)
46 | {
47 | this.userId = userId;
48 | }
49 |
50 | public String getLogin()
51 | {
52 | return login;
53 | }
54 |
55 | public void setLogin(String login)
56 | {
57 | this.login = login;
58 | }
59 |
60 | public Date getCreated()
61 | {
62 | return created;
63 | }
64 |
65 | public void setCreated(Date created)
66 | {
67 | this.created = created;
68 | }
69 | }
70 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/domain/UserAction.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.domain;
17 |
18 | import java.util.Date;
19 |
20 | /**
21 | * @author ilya40umov
22 | */
23 | public class UserAction
24 | {
25 | private int userActionId;
26 | private int userSessionId;
27 | private ActionType action;
28 | private Date created;
29 |
30 | public UserAction()
31 | {
32 |
33 | }
34 |
35 | public UserAction(int userSessionId, ActionType action, Date created)
36 | {
37 | this.userSessionId = userSessionId;
38 | this.action = action;
39 | this.created = created;
40 | }
41 |
42 | public int getUserActionId()
43 | {
44 | return userActionId;
45 | }
46 |
47 | public void setUserActionId(int userActionId)
48 | {
49 | this.userActionId = userActionId;
50 | }
51 |
52 | public int getUserSessionId()
53 | {
54 | return userSessionId;
55 | }
56 |
57 | public void setUserSessionId(int userSessionId)
58 | {
59 | this.userSessionId = userSessionId;
60 | }
61 |
62 | public ActionType getAction()
63 | {
64 | return action;
65 | }
66 |
67 | public void setAction(ActionType action)
68 | {
69 | this.action = action;
70 | }
71 |
72 | public Date getCreated()
73 | {
74 | return created;
75 | }
76 |
77 | public void setCreated(Date created)
78 | {
79 | this.created = created;
80 | }
81 |
82 | public static enum ActionType
83 | {
84 | DO_LOGIN, DO_LOGOUT, GO_WALKING, GO_CHATTING, GO_DANCING, GO_IDLE
85 | }
86 |
87 | }
88 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/domain/UserSession.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.domain;
17 |
18 | import java.util.Date;
19 |
20 | /**
21 | * @author ilya40umov
22 | */
23 | public class UserSession
24 | {
25 | private int userSessionId;
26 | private int userId;
27 | private String sessionId;
28 | private Date startTime;
29 | private Date endTime;
30 |
31 | public UserSession()
32 | {
33 |
34 | }
35 |
36 | public UserSession(int userId, String sessionId, Date startTime, Date endTime)
37 | {
38 | this.userId = userId;
39 | this.sessionId = sessionId;
40 | this.startTime = startTime;
41 | this.endTime = endTime;
42 | }
43 |
44 | public int getUserSessionId()
45 | {
46 | return userSessionId;
47 | }
48 |
49 | public void setUserSessionId(int userSessionId)
50 | {
51 | this.userSessionId = userSessionId;
52 | }
53 |
54 | public int getUserId()
55 | {
56 | return userId;
57 | }
58 |
59 | public void setUserId(int userId)
60 | {
61 | this.userId = userId;
62 | }
63 |
64 | public String getSessionId()
65 | {
66 | return sessionId;
67 | }
68 |
69 | public void setSessionId(String sessionId)
70 | {
71 | this.sessionId = sessionId;
72 | }
73 |
74 | public Date getStartTime()
75 | {
76 | return startTime;
77 | }
78 |
79 | public void setStartTime(Date startTime)
80 | {
81 | this.startTime = startTime;
82 | }
83 |
84 | public Date getEndTime()
85 | {
86 | return endTime;
87 | }
88 |
89 | public void setEndTime(Date endTime)
90 | {
91 | this.endTime = endTime;
92 | }
93 | }
94 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/exceptions/TransientException.java:
--------------------------------------------------------------------------------
1 | package org.sbq.batch.exceptions;
2 |
3 | /**
4 | * @author ilya40umov
5 | */
6 | public class TransientException extends RuntimeException
7 | {
8 | public TransientException()
9 | {
10 | }
11 |
12 | public TransientException(String message)
13 | {
14 | super(message);
15 | }
16 |
17 | public TransientException(String message, Throwable cause)
18 | {
19 | super(message, cause);
20 | }
21 |
22 | public TransientException(Throwable cause)
23 | {
24 | super(cause);
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/mains/ActivityEmulator.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.mains;
17 |
18 | import org.sbq.batch.domain.User;
19 | import org.sbq.batch.configurations.ActivityEmulatorConfiguration;
20 | import org.sbq.batch.service.UserService;
21 | import org.springframework.context.ApplicationContext;
22 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
23 |
24 | import java.io.BufferedReader;
25 | import java.io.IOException;
26 | import java.io.InputStreamReader;
27 | import java.util.*;
28 | import java.util.concurrent.*;
29 | import java.util.concurrent.atomic.AtomicBoolean;
30 |
31 | /**
32 | * @author ilya40umov
33 | */
34 | public class ActivityEmulator
35 | {
36 | private final BlockingQueue blockingQueue;
37 | private final ExecutorService executor;
38 | private final ApplicationContext appCtx;
39 | private final UserService userService;
40 | private final Map userStatusByLogin;
41 |
42 | private ActivityEmulator()
43 | {
44 | super();
45 | blockingQueue = new LinkedBlockingQueue();
46 | executor = new ThreadPoolExecutor(10, 10, 0L, TimeUnit.MILLISECONDS, blockingQueue);
47 | appCtx = new AnnotationConfigApplicationContext(ActivityEmulatorConfiguration.class);
48 | userService = appCtx.getBean(UserService.class);
49 | Map writableUserStatusByLogin = new HashMap();
50 | for (User user : userService.findAllUsers())
51 | {
52 | writableUserStatusByLogin.put(user.getLogin(), new AtomicBoolean(false));
53 | }
54 | userStatusByLogin = Collections.unmodifiableMap(writableUserStatusByLogin);
55 | }
56 |
57 | public static void main(String[] vars) throws IOException
58 | {
59 | System.out.println("ActivityEmulator - STARTED.");
60 | ActivityEmulator activityEmulator = new ActivityEmulator();
61 | activityEmulator.begin();
62 | System.out.println("Enter your command: >");
63 | BufferedReader in = new BufferedReader(new InputStreamReader(System.in));
64 | String command = null;
65 | while (!"stop".equals(command = in.readLine()))
66 | {
67 | if ("status".equals(command))
68 | {
69 | List onlineUsers = new LinkedList();
70 | for (Map.Entry entry : activityEmulator.getUserStatusByLogin().entrySet())
71 | {
72 | if (entry.getValue().get())
73 | {
74 | onlineUsers.add(entry.getKey());
75 | }
76 | }
77 | System.out.println("Users online: " + Arrays.toString(onlineUsers.toArray()));
78 | System.out.println("Number of cycles left: " + activityEmulator.getBlockingQueue().size());
79 |
80 | }
81 | System.out.println("Enter your command: >");
82 | }
83 | activityEmulator.stop();
84 | System.out.println("ActivityEmulator - STOPPED.");
85 | }
86 |
87 | private void begin()
88 | {
89 | for (int i = 0; i < 100000; i++)
90 | {
91 | executor.execute(new UserEmulator());
92 | }
93 | }
94 |
95 | private void stop()
96 | {
97 | executor.shutdownNow();
98 | }
99 |
100 | public BlockingQueue getBlockingQueue()
101 | {
102 | return blockingQueue;
103 | }
104 |
105 | public ExecutorService getExecutor()
106 | {
107 | return executor;
108 | }
109 |
110 | public Map getUserStatusByLogin()
111 | {
112 | return userStatusByLogin;
113 | }
114 |
115 | private final class UserEmulator implements Runnable
116 | {
117 | private final Random rnd = new Random();
118 |
119 | @Override
120 | public void run()
121 | {
122 | String login = acquireRandomOfflineUser();
123 | try
124 | {
125 | String sessionId = userService.login(login);
126 | sleep(rnd.nextInt(10) * 100L);
127 | for (int i = 0, n = rnd.nextInt(5); i < n; i++)
128 | {
129 | switch (rnd.nextInt(4))
130 | {
131 | case 0:
132 | userService.goChatting(sessionId);
133 | break;
134 | case 1:
135 | userService.goDancing(sessionId);
136 | break;
137 | case 2:
138 | userService.goIdle(sessionId);
139 | break;
140 | case 3:
141 | userService.goWalking(sessionId);
142 | break;
143 | }
144 | sleep(rnd.nextInt(10) * 100L);
145 | }
146 | sleep(rnd.nextInt(10) * 100L);
147 | userService.logout(sessionId);
148 | } finally
149 | {
150 | releaseUser(login);
151 | }
152 | }
153 |
154 | private String acquireRandomOfflineUser()
155 | {
156 | while (true)
157 | {
158 | int nextIdx = rnd.nextInt(userStatusByLogin.values().size());
159 | int i = 0;
160 | for (Map.Entry entry : userStatusByLogin.entrySet())
161 | {
162 | i++;
163 | if (i >= nextIdx)
164 | {
165 | String login = entry.getKey();
166 | AtomicBoolean status = entry.getValue();
167 | if (!status.get())
168 | {
169 | if (status.compareAndSet(false, true))
170 | {
171 | return login;
172 | }
173 | }
174 | }
175 | }
176 | }
177 | }
178 |
179 | private void releaseUser(String login)
180 | {
181 | userStatusByLogin.get(login).set(false);
182 | }
183 |
184 | private void sleep(long delay)
185 | {
186 | try
187 | {
188 | Thread.sleep(delay);
189 | } catch (InterruptedException e)
190 | {
191 | Thread.interrupted();
192 | }
193 | }
194 | }
195 |
196 | }
197 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/mains/SchedulerRunner.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.mains;
17 |
18 | import org.sbq.batch.configurations.SchedulerRunnerConfiguration;
19 | import org.sbq.batch.scheduled.CalculateEventMetricsScheduledJob;
20 | import org.sbq.batch.scheduled.CalculateOnlineMetricsScheduledJob;
21 | import org.sbq.batch.scheduled.LongRunningBatchScheduledJob;
22 | import org.quartz.*;
23 | import org.springframework.context.ApplicationContext;
24 | import org.springframework.context.annotation.AnnotationConfigApplicationContext;
25 |
26 | import java.util.TimeZone;
27 |
28 | import static org.quartz.CronScheduleBuilder.cronSchedule;
29 | import static org.quartz.JobBuilder.newJob;
30 | import static org.quartz.SimpleScheduleBuilder.simpleSchedule;
31 | import static org.quartz.TriggerBuilder.newTrigger;
32 |
33 | /**
34 | * @author ilya40umov
35 | */
36 | public class SchedulerRunner
37 | {
38 | private final ApplicationContext appCtx;
39 | private final Scheduler scheduler;
40 |
41 | public SchedulerRunner()
42 | {
43 | super();
44 | appCtx = new AnnotationConfigApplicationContext(SchedulerRunnerConfiguration.class);
45 | scheduler = appCtx.getBean(Scheduler.class);
46 | }
47 |
48 | public static void main(String[] args) throws SchedulerException
49 | {
50 | SchedulerRunner schedulerRunner = new SchedulerRunner();
51 | schedulerRunner.invoke();
52 | }
53 |
54 | public void invoke() throws SchedulerException
55 | {
56 | scheduleCalculateEvent();
57 | scheduleCalculateOnlineMetrics();
58 | scheduleLongRunningBatch();
59 | scheduler.start();
60 | }
61 |
62 | private void scheduleCalculateEvent() throws SchedulerException
63 | {
64 | JobDetail job = newJob(CalculateEventMetricsScheduledJob.class)
65 | .withIdentity("calculateEventMetricsScheduledJob", "MetricsCollectors")
66 | .requestRecovery(false)
67 | .build();
68 | CronTrigger trigger = newTrigger()
69 | .withIdentity("triggerFor_calculateEventMetricsScheduledJob", "MetricsCollectors")
70 | .withSchedule(cronSchedule("0 0/5 * * * ?").inTimeZone(TimeZone.getTimeZone("UTC"))
71 | .withMisfireHandlingInstructionFireAndProceed())
72 | .forJob(job.getKey())
73 | .build();
74 | trigger.getJobDataMap().putAsString("finishedAt", System.currentTimeMillis());
75 | scheduleJobWithTriggerIfNotPresent(job, trigger);
76 | }
77 |
78 | private void scheduleCalculateOnlineMetrics() throws SchedulerException
79 | {
80 | JobDetail job = newJob(CalculateOnlineMetricsScheduledJob.class)
81 | .withIdentity("calculateOnlineMetricsScheduledJob", "MetricsCollectors")
82 | .requestRecovery(false)
83 | .build();
84 | CronTrigger trigger = newTrigger()
85 | .withIdentity("triggerFor_calculateOnlineMetricsScheduledJob", "MetricsCollectors")
86 | .withSchedule(cronSchedule("0/15 * * * * ?").inTimeZone(TimeZone.getTimeZone("UTC"))
87 | .withMisfireHandlingInstructionIgnoreMisfires())
88 | .forJob(job.getKey())
89 | .build();
90 | scheduleJobWithTriggerIfNotPresent(job, trigger);
91 | }
92 |
93 | private void scheduleLongRunningBatch() throws SchedulerException
94 | {
95 | JobDetail job = newJob(LongRunningBatchScheduledJob.class)
96 | .withIdentity("longRunningBatchScheduledJob", "MetricsCollectors")
97 | .requestRecovery(true)
98 | .build();
99 | Trigger trigger = newTrigger()
100 | .withIdentity("triggerFor_longRunningBatchScheduledJob", "MetricsCollectors")
101 | .withSchedule(simpleSchedule().withIntervalInMilliseconds(500L))
102 | .forJob(job.getKey())
103 | .build();
104 | scheduleJobWithTriggerIfNotPresent(job, trigger);
105 | }
106 |
107 | private void scheduleJobWithTriggerIfNotPresent(JobDetail job, Trigger trigger) throws SchedulerException
108 | {
109 | if (!scheduler.checkExists(job.getKey()) && !scheduler.checkExists(trigger.getKey()))
110 | {
111 | try
112 | {
113 | scheduler.scheduleJob(job, trigger);
114 | } catch (ObjectAlreadyExistsException existsExc)
115 | {
116 | System.out.println("Someone has already scheduled such job/trigger. " + job.getKey() + " : " + trigger.getKey());
117 | }
118 | }
119 | }
120 | }
121 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/scheduled/AbstractScheduledJob.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.scheduled;
17 |
18 | import org.springframework.batch.core.configuration.JobRegistry;
19 | import org.springframework.batch.core.explore.JobExplorer;
20 | import org.springframework.batch.core.launch.JobLauncher;
21 | import org.springframework.batch.core.launch.JobOperator;
22 | import org.springframework.batch.core.repository.JobRepository;
23 | import org.springframework.context.ApplicationContext;
24 | import org.springframework.scheduling.quartz.QuartzJobBean;
25 |
26 | /**
27 | * @author ilya40umov
28 | */
29 | public abstract class AbstractScheduledJob extends QuartzJobBean
30 | {
31 | private ApplicationContext applicationContext;
32 |
33 | public void setApplicationContext(ApplicationContext applicationContext)
34 | {
35 | this.applicationContext = applicationContext;
36 | }
37 |
38 | protected ApplicationContext getApplicationContext()
39 | {
40 | return applicationContext;
41 | }
42 |
43 | protected JobRegistry getJobRegistry()
44 | {
45 | return applicationContext.getBean(JobRegistry.class);
46 | }
47 |
48 | protected JobLauncher getJobLauncher()
49 | {
50 | return applicationContext.getBean(JobLauncher.class);
51 | }
52 |
53 | protected JobExplorer getJobExplorer()
54 | {
55 | return applicationContext.getBean(JobExplorer.class);
56 | }
57 |
58 | protected JobOperator getJobOperator()
59 | {
60 | return applicationContext.getBean(JobOperator.class);
61 | }
62 |
63 | protected JobRepository getJobRepository()
64 | {
65 | return applicationContext.getBean(JobRepository.class);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/scheduled/CalculateEventMetricsScheduledJob.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.scheduled;
17 |
18 | import org.quartz.DisallowConcurrentExecution;
19 | import org.quartz.JobExecutionContext;
20 | import org.quartz.JobExecutionException;
21 | import org.quartz.PersistJobDataAfterExecution;
22 | import org.springframework.batch.core.JobParameter;
23 | import org.springframework.batch.core.JobParameters;
24 | import org.springframework.batch.core.configuration.JobRegistry;
25 | import org.springframework.batch.core.launch.JobLauncher;
26 |
27 | import java.util.Date;
28 | import java.util.HashMap;
29 | import java.util.Map;
30 |
31 | /**
32 | * @author ilya40umov
33 | */
34 | @DisallowConcurrentExecution // because we store job state between executions
35 | @PersistJobDataAfterExecution // because we store last fire time between executions
36 | public class CalculateEventMetricsScheduledJob extends AbstractScheduledJob
37 | {
38 | @Override
39 | protected void executeInternal(JobExecutionContext context) throws JobExecutionException
40 | {
41 | JobRegistry jobRegistry = getJobRegistry();
42 | JobLauncher jobLauncher = getJobLauncher();
43 | long finishedAt = context.getMergedJobDataMap().getLong("finishedAt");
44 | Date startingFrom = new Date(finishedAt);
45 | Date endingAt = new Date();
46 | Map parameters = new HashMap();
47 | parameters.put("startingFrom", new JobParameter(startingFrom));
48 | parameters.put("endingAt", new JobParameter(endingAt));
49 | try
50 | {
51 | jobLauncher.run(jobRegistry.getJob("calculateEventMetricsJob"), new JobParameters(parameters));
52 | context.getMergedJobDataMap().putAsString("finishedAt", endingAt.getTime());
53 | } catch (Exception e)
54 | {
55 | throw new JobExecutionException(e);
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/scheduled/CalculateOnlineMetricsScheduledJob.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.scheduled;
17 |
18 | import org.quartz.JobExecutionContext;
19 | import org.quartz.JobExecutionException;
20 | import org.springframework.batch.core.JobParameter;
21 | import org.springframework.batch.core.JobParameters;
22 | import org.springframework.batch.core.configuration.JobRegistry;
23 | import org.springframework.batch.core.launch.JobLauncher;
24 |
25 | import java.util.HashMap;
26 | import java.util.Map;
27 |
28 | /**
29 | * @author ilya40umov
30 | */
31 | // @DisallowConcurrentExecution - no need for this because jobs don't intersect
32 | // @PersistJobDataAfterExecution - don't store any data between executions
33 | public class CalculateOnlineMetricsScheduledJob extends AbstractScheduledJob
34 | {
35 | @Override
36 | protected void executeInternal(JobExecutionContext context) throws JobExecutionException
37 | {
38 | JobRegistry jobRegistry = getJobRegistry();
39 | JobLauncher jobLauncher = getJobLauncher();
40 | Map parameters = new HashMap();
41 | parameters.put("scheduledFireTime", new JobParameter(context.getScheduledFireTime()));
42 | try
43 | {
44 | jobLauncher.run(jobRegistry.getJob("calculateOnlineMetricsJob"), new JobParameters(parameters));
45 | } catch (Exception e)
46 | {
47 | throw new JobExecutionException(e);
48 | }
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/scheduled/LongRunningBatchScheduledJob.java:
--------------------------------------------------------------------------------
1 | package org.sbq.batch.scheduled;
2 |
3 | import org.quartz.DisallowConcurrentExecution;
4 | import org.quartz.JobExecutionContext;
5 | import org.quartz.JobExecutionException;
6 | import org.springframework.batch.core.BatchStatus;
7 | import org.springframework.batch.core.JobExecution;
8 | import org.springframework.batch.core.JobParameter;
9 | import org.springframework.batch.core.JobParameters;
10 | import org.springframework.batch.core.configuration.JobRegistry;
11 | import org.springframework.batch.core.explore.JobExplorer;
12 | import org.springframework.batch.core.launch.JobLauncher;
13 | import org.springframework.batch.core.repository.JobRepository;
14 |
15 | import java.util.Date;
16 | import java.util.HashMap;
17 | import java.util.Map;
18 | import java.util.Set;
19 |
20 | /**
21 | * @author ilya40umov
22 | */
23 | @DisallowConcurrentExecution
24 | public class LongRunningBatchScheduledJob extends AbstractScheduledJob
25 | {
26 | private final String jobName = "longRunningBatchJob";
27 |
28 | @Override
29 | protected void executeInternal(JobExecutionContext context) throws JobExecutionException
30 | {
31 | Map parameters = new HashMap();
32 | parameters.put("scheduledFireTime", new JobParameter(context.getScheduledFireTime()));
33 | runHandlingPossibleRecovery(new JobParameters(parameters));
34 | }
35 |
36 | private void runHandlingPossibleRecovery(JobParameters jobParameters) throws JobExecutionException
37 | {
38 | JobRegistry jobRegistry = getJobRegistry();
39 | JobLauncher jobLauncher = getJobLauncher();
40 | JobExplorer jobExplorer = getJobExplorer();
41 | JobRepository jobRepository = getJobRepository();
42 | try
43 | {
44 | // whenever Quartz performs a recovery process(it detects that a job was running when a server crashed and starts it again),
45 | // we need to deal with a previous job execution recorded by Spring Batch
46 |
47 | // since we have @DisallowConcurrentExecution on this job, all running instances are considered to be crashed/stuck ones.
48 | // in fact there can possibly be only one execution is running state
49 | Set runningExecutions = jobExplorer.findRunningJobExecutions(jobName);
50 | for (JobExecution runningExecution : runningExecutions)
51 | {
52 | // jobOperator.stop() is for graceful scenario,
53 | // it's not enough for our case because the job is already crashed and won't stop even if we notify it
54 | runningExecution.setStatus(BatchStatus.STOPPED);
55 | runningExecution.setEndTime(new Date());
56 | jobRepository.update(runningExecution);
57 | }
58 | // now we presumably can run the job
59 | jobLauncher.run(jobRegistry.getJob(jobName), jobParameters);
60 | } catch (Exception e)
61 | {
62 | throw new JobExecutionException(e);
63 | }
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/scheduler/QuartzSchedulerFactory.java:
--------------------------------------------------------------------------------
1 | package org.sbq.batch.scheduler;
2 |
3 | import org.springframework.beans.factory.annotation.Autowired;
4 | import org.springframework.core.io.ResourceLoader;
5 | import org.springframework.scheduling.quartz.SchedulerFactoryBean;
6 | import org.springframework.stereotype.Component;
7 | import org.springframework.transaction.PlatformTransactionManager;
8 |
9 | import javax.annotation.PostConstruct;
10 | import javax.sql.DataSource;
11 |
12 | /**
13 | * @author ilya40umov
14 | */
15 | @Component
16 | public class QuartzSchedulerFactory extends SchedulerFactoryBean
17 | {
18 | @Autowired(required = true)
19 | private DataSource dataSource;
20 |
21 | @Autowired(required = true)
22 | private PlatformTransactionManager platformTransactionManager;
23 |
24 | @Autowired(required = true)
25 | private ResourceLoader resourceLoader;
26 |
27 | /**
28 | * XXX This method is invoked by Spring before afterPropertiesSet().
29 | */
30 | @PostConstruct
31 | private void setUp()
32 | {
33 | setDataSource(dataSource);
34 | setTransactionManager(platformTransactionManager);
35 | setConfigLocation(resourceLoader.getResource("classpath:/quartz.properties"));
36 | setApplicationContextSchedulerContextKey("applicationContext");
37 | setAutoStartup(false);
38 | setWaitForJobsToCompleteOnShutdown(true);
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/service/MetricsService.java:
--------------------------------------------------------------------------------
1 | package org.sbq.batch.service;
2 |
3 | import java.util.Date;
4 |
5 | /**
6 | * @author ilya40umov
7 | */
8 | public interface MetricsService
9 | {
10 | void calculateEventMetrics(Date startingFrom, Date endingAt);
11 |
12 | void calculateOnlineMetrics(Date at);
13 |
14 | }
15 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/service/UserService.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.service;
17 |
18 | import org.sbq.batch.domain.User;
19 |
20 | import java.util.List;
21 |
22 | /**
23 | * @author ilya40umov
24 | */
25 | public interface UserService
26 | {
27 | List findAllUsers();
28 |
29 | /**
30 | * returns sessionId
31 | */
32 | String login(String login);
33 |
34 | void logout(String sessionId);
35 |
36 | void goWalking(String sessionId);
37 |
38 | void goChatting(String sessionId);
39 |
40 | void goDancing(String sessionId);
41 |
42 | void goIdle(String sessionId);
43 | }
44 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/service/impl/MetricsServiceImpl.java:
--------------------------------------------------------------------------------
1 | package org.sbq.batch.service.impl;
2 |
3 | import org.sbq.batch.exceptions.TransientException;
4 | import org.sbq.batch.service.MetricsService;
5 | import org.springframework.stereotype.Service;
6 |
7 | import java.util.Date;
8 | import java.util.Random;
9 |
10 | /**
11 | * @author ilya40umov
12 | */
13 | @Service
14 | public class MetricsServiceImpl implements MetricsService
15 | {
16 | @Override
17 | public void calculateEventMetrics(Date startingFrom, Date endingAt)
18 | {
19 | System.out.println(">>>> calculateEventMetrics( " + startingFrom.toString() + " , " + endingAt.toString() + " )");
20 |
21 | // TODO implement the actual logic(see README.md for details)
22 | }
23 |
24 | @Override
25 | public void calculateOnlineMetrics(Date at)
26 | {
27 | System.out.println(">>>> calculateOnlineMetrics( " + at.toString() + " )");
28 | Random rnd = new Random();
29 | if (rnd.nextInt(3) == 0)
30 | {
31 | System.out.println(">>>> calculateOnlineMetrics() - TRANSIENT EXCEPTION...");
32 | throw new TransientException("This kind of problem can sometimes happen!");
33 | }
34 |
35 | // TODO implement the actual logic(see README.md for details)
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/service/impl/UserServiceImpl.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.service.impl;
17 |
18 | import org.sbq.batch.dao.UserActionDao;
19 | import org.sbq.batch.dao.UserDao;
20 | import org.sbq.batch.dao.UserSessionDao;
21 | import org.sbq.batch.domain.User;
22 | import org.sbq.batch.domain.UserAction;
23 | import org.sbq.batch.domain.UserSession;
24 | import org.sbq.batch.service.UserService;
25 | import org.springframework.beans.factory.annotation.Autowired;
26 | import org.springframework.stereotype.Service;
27 | import org.springframework.transaction.annotation.Transactional;
28 |
29 | import java.util.Date;
30 | import java.util.List;
31 | import java.util.UUID;
32 |
33 | /**
34 | * @author ilya40umov
35 | */
36 | @Service
37 | @Transactional
38 | public class UserServiceImpl implements UserService
39 | {
40 | @Autowired
41 | private UserDao userDao;
42 |
43 | @Autowired
44 | private UserSessionDao userSessionDao;
45 |
46 | @Autowired
47 | private UserActionDao userActionDao;
48 |
49 | @Override
50 | @Transactional(readOnly = true)
51 | public List findAllUsers()
52 | {
53 | return userDao.findAllUsers();
54 | }
55 |
56 | @Override
57 | public String login(String login)
58 | {
59 | Date now = new Date();
60 | User user = userDao.findUserByLogin(login);
61 | if (user != null)
62 | {
63 | String sessionId = UUID.randomUUID().toString();
64 | userSessionDao.insert(new UserSession(user.getUserId(), sessionId, now, null));
65 | int userSessionId = userSessionDao.findUserSessionBySessionId(sessionId).getUserSessionId();
66 | userActionDao.insert(new UserAction(userSessionId, UserAction.ActionType.DO_LOGIN, now));
67 | return sessionId;
68 | } else
69 | {
70 | throw new IllegalArgumentException("User with a such login is not found!");
71 | }
72 | }
73 |
74 | @Override
75 | public void logout(String sessionId)
76 | {
77 | Date now = new Date();
78 | int userSessionId = userSessionDao.findUserSessionBySessionId(sessionId).getUserSessionId();
79 | userActionDao.insert(new UserAction(userSessionId, UserAction.ActionType.DO_LOGOUT, now));
80 | userSessionDao.updateEndTime(sessionId, now);
81 | }
82 |
83 | @Override
84 | public void goWalking(String sessionId)
85 | {
86 | Date now = new Date();
87 | int userSessionId = userSessionDao.findUserSessionBySessionId(sessionId).getUserSessionId();
88 | userActionDao.insert(new UserAction(userSessionId, UserAction.ActionType.GO_WALKING, now));
89 | }
90 |
91 | @Override
92 | public void goChatting(String sessionId)
93 | {
94 | Date now = new Date();
95 | int userSessionId = userSessionDao.findUserSessionBySessionId(sessionId).getUserSessionId();
96 | userActionDao.insert(new UserAction(userSessionId, UserAction.ActionType.GO_CHATTING, now));
97 | }
98 |
99 | @Override
100 | public void goDancing(String sessionId)
101 | {
102 | Date now = new Date();
103 | int userSessionId = userSessionDao.findUserSessionBySessionId(sessionId).getUserSessionId();
104 | userActionDao.insert(new UserAction(userSessionId, UserAction.ActionType.GO_DANCING, now));
105 | }
106 |
107 | @Override
108 | public void goIdle(String sessionId)
109 | {
110 | Date now = new Date();
111 | int userSessionId = userSessionDao.findUserSessionBySessionId(sessionId).getUserSessionId();
112 | userActionDao.insert(new UserAction(userSessionId, UserAction.ActionType.GO_IDLE, now));
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/tasks/CalculateEventMetricsTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.tasks;
17 |
18 | import org.sbq.batch.service.MetricsService;
19 | import org.springframework.batch.core.StepContribution;
20 | import org.springframework.batch.core.scope.context.ChunkContext;
21 | import org.springframework.batch.core.step.tasklet.Tasklet;
22 | import org.springframework.batch.repeat.RepeatStatus;
23 | import org.springframework.beans.factory.annotation.Autowired;
24 |
25 | import java.util.Date;
26 |
27 | /**
28 | * @author ilya40umov
29 | */
30 | public class CalculateEventMetricsTask implements Tasklet
31 | {
32 | @Autowired
33 | private MetricsService metricsService;
34 |
35 | @Override
36 | public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception
37 | {
38 | Date startingFrom = (Date) chunkContext.getStepContext().getJobParameters().get("startingFrom");
39 | Date endingAt = (Date) chunkContext.getStepContext().getJobParameters().get("endingAt");
40 | metricsService.calculateEventMetrics(startingFrom, endingAt);
41 | return RepeatStatus.FINISHED;
42 | }
43 |
44 | }
45 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/tasks/CalculateOnlineMetricsTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.tasks;
17 |
18 | import org.sbq.batch.service.MetricsService;
19 | import org.springframework.batch.core.StepContribution;
20 | import org.springframework.batch.core.scope.context.ChunkContext;
21 | import org.springframework.batch.core.step.tasklet.Tasklet;
22 | import org.springframework.batch.repeat.RepeatStatus;
23 | import org.springframework.beans.factory.annotation.Autowired;
24 |
25 | import java.util.Date;
26 |
27 | /**
28 | * @author ilya40umov
29 | */
30 | public class CalculateOnlineMetricsTask implements Tasklet
31 | {
32 | @Autowired
33 | private MetricsService metricsService;
34 |
35 | @Override
36 | public RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception
37 | {
38 | Date scheduledFireTime = (Date) chunkContext.getStepContext().getJobParameters().get("scheduledFireTime");
39 | metricsService.calculateOnlineMetrics(scheduledFireTime);
40 | return RepeatStatus.FINISHED;
41 | }
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/java/org/sbq/batch/tasks/LongRunningBatchTask.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright 2013 the original author or authors.
3 | *
4 | * Licensed under the Apache License, Version 2.0 (the "License");
5 | * you may not use this file except in compliance with the License.
6 | * You may obtain a copy of the License at
7 | *
8 | * http://www.apache.org/licenses/LICENSE-2.0
9 | *
10 | * Unless required by applicable law or agreed to in writing, software
11 | * distributed under the License is distributed on an "AS IS" BASIS,
12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | * See the License for the specific language governing permissions and
14 | * limitations under the License.
15 | */
16 | package org.sbq.batch.tasks;
17 |
18 | import org.springframework.batch.core.StepContribution;
19 | import org.springframework.batch.core.scope.context.ChunkContext;
20 | import org.springframework.batch.core.step.tasklet.Tasklet;
21 | import org.springframework.batch.repeat.RepeatStatus;
22 |
23 | import java.util.Date;
24 |
25 | /**
26 | * @author ilya40umov
27 | */
28 | public class LongRunningBatchTask implements Tasklet
29 | {
30 | @Override
31 | public RepeatStatus execute(StepContribution contribution, ChunkContext chunkContext) throws Exception
32 | {
33 | Date scheduledFireTime = (Date) chunkContext.getStepContext().getJobParameters().get("scheduledFireTime");
34 | System.out.println(">>>> LongRunningBatchTask.execute( " + scheduledFireTime.toString() + " )");
35 | int i = 0;
36 | while (i < 600) // we don't pay attention if we are interrupted
37 | {
38 | i++;
39 | try
40 | {
41 | Thread.sleep(1000L);
42 | } catch (InterruptedException e)
43 | {
44 | Thread.interrupted();
45 | }
46 | }
47 | return RepeatStatus.FINISHED;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/resources/init.sql:
--------------------------------------------------------------------------------
1 | #
2 | # Copyright 2013 the original author or authors.
3 | #
4 | # Licensed under the Apache License, Version 2.0 (the "License");
5 | # you may not use this file except in compliance with the License.
6 | # You may obtain a copy of the License at
7 | #
8 | # http://www.apache.org/licenses/LICENSE-2.0
9 | #
10 | # Unless required by applicable law or agreed to in writing, software
11 | # distributed under the License is distributed on an "AS IS" BASIS,
12 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | # See the License for the specific language governing permissions and
14 | # limitations under the License.
15 | #
16 |
17 | #
18 | # DB init script
19 | #
20 |
21 | DROP SCHEMA IF EXISTS `batch_db`;
22 | CREATE SCHEMA `batch_db`
23 | DEFAULT CHARACTER SET utf8;
24 | USE `batch_db`;
25 |
26 | #
27 | # Quartz tables, indexes etc.
28 | #
29 |
30 | DROP TABLE IF EXISTS QRTZ_FIRED_TRIGGERS;
31 | DROP TABLE IF EXISTS QRTZ_PAUSED_TRIGGER_GRPS;
32 | DROP TABLE IF EXISTS QRTZ_SCHEDULER_STATE;
33 | DROP TABLE IF EXISTS QRTZ_LOCKS;
34 | DROP TABLE IF EXISTS QRTZ_SIMPLE_TRIGGERS;
35 | DROP TABLE IF EXISTS QRTZ_SIMPROP_TRIGGERS;
36 | DROP TABLE IF EXISTS QRTZ_CRON_TRIGGERS;
37 | DROP TABLE IF EXISTS QRTZ_BLOB_TRIGGERS;
38 | DROP TABLE IF EXISTS QRTZ_TRIGGERS;
39 | DROP TABLE IF EXISTS QRTZ_JOB_DETAILS;
40 | DROP TABLE IF EXISTS QRTZ_CALENDARS;
41 |
42 | CREATE TABLE QRTZ_JOB_DETAILS (
43 | SCHED_NAME VARCHAR(120) NOT NULL,
44 | JOB_NAME VARCHAR(200) NOT NULL,
45 | JOB_GROUP VARCHAR(200) NOT NULL,
46 | DESCRIPTION VARCHAR(250) NULL,
47 | JOB_CLASS_NAME VARCHAR(250) NOT NULL,
48 | IS_DURABLE VARCHAR(1) NOT NULL,
49 | IS_NONCONCURRENT VARCHAR(1) NOT NULL,
50 | IS_UPDATE_DATA VARCHAR(1) NOT NULL,
51 | REQUESTS_RECOVERY VARCHAR(1) NOT NULL,
52 | JOB_DATA BLOB NULL,
53 | PRIMARY KEY (SCHED_NAME, JOB_NAME, JOB_GROUP))
54 | ENGINE = InnoDB;
55 |
56 | CREATE TABLE QRTZ_TRIGGERS (
57 | SCHED_NAME VARCHAR(120) NOT NULL,
58 | TRIGGER_NAME VARCHAR(200) NOT NULL,
59 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
60 | JOB_NAME VARCHAR(200) NOT NULL,
61 | JOB_GROUP VARCHAR(200) NOT NULL,
62 | DESCRIPTION VARCHAR(250) NULL,
63 | NEXT_FIRE_TIME BIGINT(13) NULL,
64 | PREV_FIRE_TIME BIGINT(13) NULL,
65 | PRIORITY INTEGER NULL,
66 | TRIGGER_STATE VARCHAR(16) NOT NULL,
67 | TRIGGER_TYPE VARCHAR(8) NOT NULL,
68 | START_TIME BIGINT(13) NOT NULL,
69 | END_TIME BIGINT(13) NULL,
70 | CALENDAR_NAME VARCHAR(200) NULL,
71 | MISFIRE_INSTR SMALLINT(2) NULL,
72 | JOB_DATA BLOB NULL,
73 | PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
74 | INDEX (SCHED_NAME, JOB_NAME, JOB_GROUP),
75 | FOREIGN KEY (SCHED_NAME, JOB_NAME, JOB_GROUP)
76 | REFERENCES QRTZ_JOB_DETAILS (SCHED_NAME, JOB_NAME, JOB_GROUP))
77 | ENGINE = InnoDB;
78 |
79 | CREATE TABLE QRTZ_SIMPLE_TRIGGERS (
80 | SCHED_NAME VARCHAR(120) NOT NULL,
81 | TRIGGER_NAME VARCHAR(200) NOT NULL,
82 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
83 | REPEAT_COUNT BIGINT(7) NOT NULL,
84 | REPEAT_INTERVAL BIGINT(12) NOT NULL,
85 | TIMES_TRIGGERED BIGINT(10) NOT NULL,
86 | PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
87 | INDEX (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
88 | FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
89 | REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP))
90 | ENGINE = InnoDB;
91 |
92 | CREATE TABLE QRTZ_CRON_TRIGGERS (
93 | SCHED_NAME VARCHAR(120) NOT NULL,
94 | TRIGGER_NAME VARCHAR(200) NOT NULL,
95 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
96 | CRON_EXPRESSION VARCHAR(120) NOT NULL,
97 | TIME_ZONE_ID VARCHAR(80),
98 | PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
99 | INDEX (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
100 | FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
101 | REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP))
102 | ENGINE = InnoDB;
103 |
104 | CREATE TABLE QRTZ_SIMPROP_TRIGGERS
105 | (
106 | SCHED_NAME VARCHAR(120) NOT NULL,
107 | TRIGGER_NAME VARCHAR(200) NOT NULL,
108 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
109 | STR_PROP_1 VARCHAR(512) NULL,
110 | STR_PROP_2 VARCHAR(512) NULL,
111 | STR_PROP_3 VARCHAR(512) NULL,
112 | INT_PROP_1 INT NULL,
113 | INT_PROP_2 INT NULL,
114 | LONG_PROP_1 BIGINT NULL,
115 | LONG_PROP_2 BIGINT NULL,
116 | DEC_PROP_1 NUMERIC(13, 4) NULL,
117 | DEC_PROP_2 NUMERIC(13, 4) NULL,
118 | BOOL_PROP_1 VARCHAR(1) NULL,
119 | BOOL_PROP_2 VARCHAR(1) NULL,
120 | PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
121 | FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
122 | REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP))
123 | ENGINE = InnoDB;
124 |
125 | CREATE TABLE QRTZ_BLOB_TRIGGERS (
126 | SCHED_NAME VARCHAR(120) NOT NULL,
127 | TRIGGER_NAME VARCHAR(200) NOT NULL,
128 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
129 | BLOB_DATA BLOB NULL,
130 | PRIMARY KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
131 | INDEX (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP),
132 | FOREIGN KEY (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP)
133 | REFERENCES QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP))
134 | ENGINE = InnoDB;
135 |
136 | CREATE TABLE QRTZ_CALENDARS (
137 | SCHED_NAME VARCHAR(120) NOT NULL,
138 | CALENDAR_NAME VARCHAR(200) NOT NULL,
139 | CALENDAR BLOB NOT NULL,
140 | PRIMARY KEY (SCHED_NAME, CALENDAR_NAME))
141 | ENGINE = InnoDB;
142 |
143 | CREATE TABLE QRTZ_PAUSED_TRIGGER_GRPS (
144 | SCHED_NAME VARCHAR(120) NOT NULL,
145 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
146 | PRIMARY KEY (SCHED_NAME, TRIGGER_GROUP))
147 | ENGINE = InnoDB;
148 |
149 | CREATE TABLE QRTZ_FIRED_TRIGGERS (
150 | SCHED_NAME VARCHAR(120) NOT NULL,
151 | ENTRY_ID VARCHAR(95) NOT NULL,
152 | TRIGGER_NAME VARCHAR(200) NOT NULL,
153 | TRIGGER_GROUP VARCHAR(200) NOT NULL,
154 | INSTANCE_NAME VARCHAR(200) NOT NULL,
155 | FIRED_TIME BIGINT(13) NOT NULL,
156 | PRIORITY INTEGER NOT NULL,
157 | STATE VARCHAR(16) NOT NULL,
158 | JOB_NAME VARCHAR(200) NULL,
159 | JOB_GROUP VARCHAR(200) NULL,
160 | IS_NONCONCURRENT VARCHAR(1) NULL,
161 | REQUESTS_RECOVERY VARCHAR(1) NULL,
162 | PRIMARY KEY (SCHED_NAME, ENTRY_ID))
163 | ENGINE = InnoDB;
164 |
165 | CREATE TABLE QRTZ_SCHEDULER_STATE (
166 | SCHED_NAME VARCHAR(120) NOT NULL,
167 | INSTANCE_NAME VARCHAR(200) NOT NULL,
168 | LAST_CHECKIN_TIME BIGINT(13) NOT NULL,
169 | CHECKIN_INTERVAL BIGINT(13) NOT NULL,
170 | PRIMARY KEY (SCHED_NAME, INSTANCE_NAME))
171 | ENGINE = InnoDB;
172 |
173 | CREATE TABLE QRTZ_LOCKS (
174 | SCHED_NAME VARCHAR(120) NOT NULL,
175 | LOCK_NAME VARCHAR(40) NOT NULL,
176 | PRIMARY KEY (SCHED_NAME, LOCK_NAME))
177 | ENGINE = InnoDB;
178 |
179 | CREATE INDEX IDX_QRTZ_J_REQ_RECOVERY ON QRTZ_JOB_DETAILS (SCHED_NAME, REQUESTS_RECOVERY);
180 | CREATE INDEX IDX_QRTZ_J_GRP ON QRTZ_JOB_DETAILS (SCHED_NAME, JOB_GROUP);
181 |
182 | CREATE INDEX IDX_QRTZ_T_J ON QRTZ_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
183 | CREATE INDEX IDX_QRTZ_T_JG ON QRTZ_TRIGGERS (SCHED_NAME, JOB_GROUP);
184 | CREATE INDEX IDX_QRTZ_T_C ON QRTZ_TRIGGERS (SCHED_NAME, CALENDAR_NAME);
185 | CREATE INDEX IDX_QRTZ_T_G ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
186 | CREATE INDEX IDX_QRTZ_T_STATE ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE);
187 | CREATE INDEX IDX_QRTZ_T_N_STATE ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP, TRIGGER_STATE);
188 | CREATE INDEX IDX_QRTZ_T_N_G_STATE ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_GROUP, TRIGGER_STATE);
189 | CREATE INDEX IDX_QRTZ_T_NEXT_FIRE_TIME ON QRTZ_TRIGGERS (SCHED_NAME, NEXT_FIRE_TIME);
190 | CREATE INDEX IDX_QRTZ_T_NFT_ST ON QRTZ_TRIGGERS (SCHED_NAME, TRIGGER_STATE, NEXT_FIRE_TIME);
191 | CREATE INDEX IDX_QRTZ_T_NFT_MISFIRE ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME);
192 | CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_STATE);
193 | CREATE INDEX IDX_QRTZ_T_NFT_ST_MISFIRE_GRP ON QRTZ_TRIGGERS (SCHED_NAME, MISFIRE_INSTR, NEXT_FIRE_TIME, TRIGGER_GROUP, TRIGGER_STATE);
194 |
195 | CREATE INDEX IDX_QRTZ_FT_TRIG_INST_NAME ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME);
196 | CREATE INDEX IDX_QRTZ_FT_INST_JOB_REQ_RCVRY ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, INSTANCE_NAME, REQUESTS_RECOVERY);
197 | CREATE INDEX IDX_QRTZ_FT_J_G ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_NAME, JOB_GROUP);
198 | CREATE INDEX IDX_QRTZ_FT_JG ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, JOB_GROUP);
199 | CREATE INDEX IDX_QRTZ_FT_T_G ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_NAME, TRIGGER_GROUP);
200 | CREATE INDEX IDX_QRTZ_FT_TG ON QRTZ_FIRED_TRIGGERS (SCHED_NAME, TRIGGER_GROUP);
201 |
202 | #
203 | # Spring Batch Tables, Indexes etc.
204 | #
205 |
206 | DROP TABLE IF EXISTS BATCH_STEP_EXECUTION_CONTEXT ;
207 | DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_CONTEXT ;
208 | DROP TABLE IF EXISTS BATCH_STEP_EXECUTION ;
209 | DROP TABLE IF EXISTS BATCH_JOB_EXECUTION ;
210 | DROP TABLE IF EXISTS BATCH_JOB_PARAMS ;
211 | DROP TABLE IF EXISTS BATCH_JOB_INSTANCE ;
212 |
213 | DROP TABLE IF EXISTS BATCH_STEP_EXECUTION_SEQ ;
214 | DROP TABLE IF EXISTS BATCH_JOB_EXECUTION_SEQ ;
215 | DROP TABLE IF EXISTS BATCH_JOB_SEQ ;
216 |
217 | CREATE TABLE BATCH_JOB_INSTANCE (
218 | JOB_INSTANCE_ID BIGINT NOT NULL PRIMARY KEY ,
219 | VERSION BIGINT ,
220 | JOB_NAME VARCHAR(100) NOT NULL,
221 | JOB_KEY VARCHAR(32) NOT NULL,
222 | constraint JOB_INST_UN unique (JOB_NAME, JOB_KEY)
223 | ) ENGINE=InnoDB;
224 |
225 | CREATE TABLE BATCH_JOB_EXECUTION (
226 | JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,
227 | VERSION BIGINT ,
228 | JOB_INSTANCE_ID BIGINT NOT NULL,
229 | CREATE_TIME DATETIME NOT NULL,
230 | START_TIME DATETIME DEFAULT NULL ,
231 | END_TIME DATETIME DEFAULT NULL ,
232 | STATUS VARCHAR(10) ,
233 | EXIT_CODE VARCHAR(100) ,
234 | EXIT_MESSAGE VARCHAR(2500) ,
235 | LAST_UPDATED DATETIME,
236 | constraint JOB_INST_EXEC_FK foreign key (JOB_INSTANCE_ID)
237 | references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
238 | ) ENGINE=InnoDB;
239 |
240 | CREATE TABLE BATCH_JOB_PARAMS (
241 | JOB_INSTANCE_ID BIGINT NOT NULL ,
242 | TYPE_CD VARCHAR(6) NOT NULL ,
243 | KEY_NAME VARCHAR(100) NOT NULL ,
244 | STRING_VAL VARCHAR(250) ,
245 | DATE_VAL DATETIME DEFAULT NULL ,
246 | LONG_VAL BIGINT ,
247 | DOUBLE_VAL DOUBLE PRECISION ,
248 | constraint JOB_INST_PARAMS_FK foreign key (JOB_INSTANCE_ID)
249 | references BATCH_JOB_INSTANCE(JOB_INSTANCE_ID)
250 | ) ENGINE=InnoDB;
251 |
252 | CREATE TABLE BATCH_STEP_EXECUTION (
253 | STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY ,
254 | VERSION BIGINT NOT NULL,
255 | STEP_NAME VARCHAR(100) NOT NULL,
256 | JOB_EXECUTION_ID BIGINT NOT NULL,
257 | START_TIME DATETIME NOT NULL ,
258 | END_TIME DATETIME DEFAULT NULL ,
259 | STATUS VARCHAR(10) ,
260 | COMMIT_COUNT BIGINT ,
261 | READ_COUNT BIGINT ,
262 | FILTER_COUNT BIGINT ,
263 | WRITE_COUNT BIGINT ,
264 | READ_SKIP_COUNT BIGINT ,
265 | WRITE_SKIP_COUNT BIGINT ,
266 | PROCESS_SKIP_COUNT BIGINT ,
267 | ROLLBACK_COUNT BIGINT ,
268 | EXIT_CODE VARCHAR(100) ,
269 | EXIT_MESSAGE VARCHAR(2500) ,
270 | LAST_UPDATED DATETIME,
271 | constraint JOB_EXEC_STEP_FK foreign key (JOB_EXECUTION_ID)
272 | references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
273 | ) ENGINE=InnoDB;
274 |
275 | CREATE TABLE BATCH_STEP_EXECUTION_CONTEXT (
276 | STEP_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
277 | SHORT_CONTEXT VARCHAR(2500) NOT NULL,
278 | SERIALIZED_CONTEXT TEXT ,
279 | constraint STEP_EXEC_CTX_FK foreign key (STEP_EXECUTION_ID)
280 | references BATCH_STEP_EXECUTION(STEP_EXECUTION_ID)
281 | ) ENGINE=InnoDB;
282 |
283 | CREATE TABLE BATCH_JOB_EXECUTION_CONTEXT (
284 | JOB_EXECUTION_ID BIGINT NOT NULL PRIMARY KEY,
285 | SHORT_CONTEXT VARCHAR(2500) NOT NULL,
286 | SERIALIZED_CONTEXT TEXT ,
287 | constraint JOB_EXEC_CTX_FK foreign key (JOB_EXECUTION_ID)
288 | references BATCH_JOB_EXECUTION(JOB_EXECUTION_ID)
289 | ) ENGINE=InnoDB;
290 |
291 | CREATE TABLE BATCH_STEP_EXECUTION_SEQ (ID BIGINT NOT NULL) ENGINE=MYISAM;
292 | INSERT INTO BATCH_STEP_EXECUTION_SEQ values(0);
293 | CREATE TABLE BATCH_JOB_EXECUTION_SEQ (ID BIGINT NOT NULL) ENGINE=MYISAM;
294 | INSERT INTO BATCH_JOB_EXECUTION_SEQ values(0);
295 | CREATE TABLE BATCH_JOB_SEQ (ID BIGINT NOT NULL) ENGINE=MYISAM;
296 | INSERT INTO BATCH_JOB_SEQ values(0);
297 |
298 | #
299 | # Test application tables, indexes etc.
300 | #
301 |
302 | CREATE TABLE `SBQ_USER` (
303 | `USER_ID` INT NOT NULL AUTO_INCREMENT,
304 | `LOGIN` VARCHAR(45) NOT NULL,
305 | `CREATED` DATETIME NOT NULL,
306 | PRIMARY KEY (`USER_ID`),
307 | UNIQUE INDEX `login_UNIQUE` (`LOGIN` ASC));
308 |
309 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user1', NOW());
310 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user2', NOW());
311 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user3', NOW());
312 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user4', NOW());
313 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user5', NOW());
314 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user6', NOW());
315 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user7', NOW());
316 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user8', NOW());
317 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user9', NOW());
318 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user10', NOW());
319 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user11', NOW());
320 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user12', NOW());
321 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user13', NOW());
322 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user14', NOW());
323 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user15', NOW());
324 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user16', NOW());
325 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user17', NOW());
326 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user18', NOW());
327 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user19', NOW());
328 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user20', NOW());
329 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user01', NOW());
330 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user02', NOW());
331 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user03', NOW());
332 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user04', NOW());
333 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user05', NOW());
334 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user06', NOW());
335 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user07', NOW());
336 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user08', NOW());
337 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user09', NOW());
338 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user010', NOW());
339 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user011', NOW());
340 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user012', NOW());
341 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user013', NOW());
342 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user014', NOW());
343 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user015', NOW());
344 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user016', NOW());
345 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user017', NOW());
346 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user018', NOW());
347 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user019', NOW());
348 | INSERT INTO `SBQ_USER` (`LOGIN`, `CREATED`) VALUES ('user020', NOW());
349 |
350 | CREATE TABLE `SBQ_USER_SESSION` (
351 | `USER_SESSION_ID` INT NOT NULL AUTO_INCREMENT,
352 | `USER_ID` INT NOT NULL,
353 | `SESSION_ID` VARCHAR(64) NOT NULL,
354 | `START_TIME` DATETIME NOT NULL,
355 | `END_TIME` DATETIME NULL DEFAULT NULL,
356 | PRIMARY KEY (`USER_SESSION_ID`),
357 | INDEX `FK_USER_ID_IDX` (`USER_ID` ASC),
358 | CONSTRAINT `FK_USER_ID`
359 | FOREIGN KEY (`USER_ID`)
360 | REFERENCES `SBQ_USER` (`USER_ID`)
361 | ON DELETE NO ACTION
362 | ON UPDATE NO ACTION);
363 |
364 | CREATE TABLE `SBQ_USER_ACTION` (
365 | `USER_ACTION_ID` INT NOT NULL AUTO_INCREMENT,
366 | `USER_SESSION_ID` INT NOT NULL,
367 | `ACTION` VARCHAR(45) NOT NULL,
368 | `CREATED` DATETIME NOT NULL,
369 | PRIMARY KEY (`USER_ACTION_ID`),
370 | INDEX `FK_USER_SESSION_ID_IDX` (`USER_SESSION_ID` ASC),
371 | CONSTRAINT `FK_USER_SESSION_ID`
372 | FOREIGN KEY (`USER_SESSION_ID`)
373 | REFERENCES `SBQ_USER_SESSION` (`USER_SESSION_ID`)
374 | ON DELETE NO ACTION
375 | ON UPDATE NO ACTION);
376 |
377 | COMMIT;
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/resources/log4j.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/resources/quartz.properties:
--------------------------------------------------------------------------------
1 | #============================================================================
2 | # Configure Main Scheduler Properties
3 | #============================================================================
4 |
5 | org.quartz.scheduler.instanceName = SpringBatchClusteredScheduler
6 | org.quartz.scheduler.instanceId = AUTO
7 |
8 | #============================================================================
9 | # Configure ThreadPool
10 | #============================================================================
11 |
12 | org.quartz.threadPool.class = org.quartz.simpl.SimpleThreadPool
13 | org.quartz.threadPool.threadCount = 10
14 | org.quartz.threadPool.threadPriority = 5
15 | org.quartz.threadPool.threadsInheritContextClassLoaderOfInitializingThread = true
16 |
17 | #============================================================================
18 | # Configure JobStore
19 | #============================================================================
20 |
21 | # org.quartz.jobStore.class is set by SchedulerFactoryBean
22 |
23 | # 'useProperties=true' means that all JobData is of String type to avoid incompatible Serializable
24 | org.quartz.jobStore.useProperties = true
25 | org.quartz.jobStore.tablePrefix = QRTZ_
26 | org.quartz.jobStore.driverDelegateClass = org.quartz.impl.jdbcjobstore.StdJDBCDelegate
27 | # 10 minutes
28 | org.quartz.jobStore.misfireThreshold = 600000
29 |
30 | org.quartz.jobStore.isClustered = true
31 | # 10 secs
32 | org.quartz.jobStore.clusterCheckinInterval = 10000
33 |
34 | #============================================================================
35 | # Configure Job History Plugin
36 | #============================================================================
37 |
38 | org.quartz.plugin.jobHistory.class = org.quartz.plugins.history.LoggingJobHistoryPlugin
39 | org.quartz.plugin.jobHistory.jobSuccessMessage = Job {1}.{0} fired at: {2, date, dd/MM/yyyy HH:mm:ss} result=OK
40 | org.quartz.plugin.jobHistory.jobFailedMessage = Job {1}.{0} fired at: {2, date, dd/MM/yyyy HH:mm:ss} result=ERROR
--------------------------------------------------------------------------------
/spring-batch-quartz-example/src/main/resources/spring-batch-conf.xml:
--------------------------------------------------------------------------------
1 |
2 |
9 |
10 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
36 |
37 |
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 |
77 |
78 |
79 |
80 |
81 |
82 | Initial sleep interval value, default 300 ms
83 |
84 |
85 | The maximum value of the backoff period in milliseconds.
86 |
87 |
88 | The value to increment the exp seed with for each retry attempt.
89 |
90 |
91 |
92 |
94 |
95 |
96 |
97 |
98 |
100 |
102 |
103 |
104 |
105 |
--------------------------------------------------------------------------------