Skip to content

Commit e072b3d

Browse files
angryziberxael-fry
authored andcommitted
* Better support for jobs with multiple annotations, e.g. @OnApplicationStart and @every
* Previously these jobs would be displayed twice in application status. * refactor(JobPlugin):Fixed some compiler warnings * refactor(JobPlugin): Create executor and scheduledJobs at the same time to prevent unexpected NPEs during startup * refactor(JobPlugin):Be consistent with how jobs are displayed in application status: use toString() in both 'Scheduled jobs' and 'Waiting jobs' * refactor(JobPlugin):Make JobsPlugin aware of Jobs scheduled programmatically with Job.every() and display them in application status * refactor(JobPlugin): Use Job.toString() also in monitor name, for consistency with Scheduled Jobs and Waiting Jobs Conflicts: framework/src/play/jobs/Job.java
1 parent f963059 commit e072b3d

File tree

2 files changed

+28
-27
lines changed

2 files changed

+28
-27
lines changed

framework/src/play/jobs/Job.java

+2-1
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ public void every(String delay) {
140140
*/
141141
public void every(int seconds) {
142142
JobsPlugin.executor.scheduleWithFixedDelay(this, seconds, seconds, TimeUnit.SECONDS);
143+
JobsPlugin.scheduledJobs.add(this);
143144
}
144145

145146
// Customize Invocation
@@ -177,7 +178,7 @@ public V call() {
177178
try {
178179
lastException = null;
179180
lastRun = System.currentTimeMillis();
180-
monitor = MonitorFactory.start(getClass().getName()+".doJob()");
181+
monitor = MonitorFactory.start(this + ".doJob()");
181182
result = doJobWithResult();
182183
monitor.stop();
183184
monitor = null;

framework/src/play/jobs/JobsPlugin.java

+26-26
Original file line numberDiff line numberDiff line change
@@ -28,9 +28,9 @@
2828

2929
public class JobsPlugin extends PlayPlugin {
3030

31-
public static ScheduledThreadPoolExecutor executor = null;
32-
public static List<Job> scheduledJobs = null;
33-
private static ThreadLocal<List<Callable<? extends Object>>> afterInvocationActions = new ThreadLocal<List<Callable<? extends Object>>>();
31+
public static ScheduledThreadPoolExecutor executor;
32+
public static List<Job> scheduledJobs;
33+
private static ThreadLocal<List<Callable<?>>> afterInvocationActions = new ThreadLocal<List<Callable<?>>>();
3434

3535
@Override
3636
public String getStatus() {
@@ -54,7 +54,7 @@ public String getStatus() {
5454
out.println("Scheduled jobs (" + scheduledJobs.size() + "):");
5555
out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~");
5656
for (Job job : scheduledJobs) {
57-
out.print(job.getClass().getName());
57+
out.print(job);
5858
if (job.getClass().isAnnotationPresent(OnApplicationStart.class)
5959
&& !(job.getClass().isAnnotationPresent(On.class) || job.getClass().isAnnotationPresent(Every.class))) {
6060
OnApplicationStart appStartAnnotation = job.getClass().getAnnotation(OnApplicationStart.class);
@@ -89,10 +89,9 @@ public String getStatus() {
8989
out.println();
9090
out.println("Waiting jobs:");
9191
out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~");
92-
ScheduledFuture[] q = executor.getQueue().toArray(new ScheduledFuture[0]);
92+
ScheduledFuture[] q = executor.getQueue().toArray(new ScheduledFuture[executor.getQueue().size()]);
9393

94-
for (int i = 0; i < q.length; i++) {
95-
ScheduledFuture task = q[i];
94+
for (ScheduledFuture task : q) {
9695
out.println(Java.extractUnderlyingCallable((FutureTask<?>) task) + " will run in " + task.getDelay(TimeUnit.SECONDS)
9796
+ " seconds");
9897
}
@@ -108,7 +107,6 @@ public void afterApplicationStart() {
108107
jobs.add(clazz);
109108
}
110109
}
111-
scheduledJobs = new ArrayList<Job>();
112110
for (final Class<?> clazz : jobs) {
113111
// @OnApplicationStart
114112
if (clazz.isAnnotationPresent(OnApplicationStart.class)) {
@@ -117,8 +115,7 @@ public void afterApplicationStart() {
117115
if (!appStartAnnotation.async()) {
118116
// run job sync
119117
try {
120-
Job<?> job = ((Job<?>) clazz.newInstance());
121-
scheduledJobs.add(job);
118+
Job<?> job = createJob(clazz);
122119
job.run();
123120
if (job.wasError) {
124121
if (job.lastException != null) {
@@ -139,8 +136,7 @@ public void afterApplicationStart() {
139136
} else {
140137
// run job async
141138
try {
142-
Job<?> job = ((Job<?>) clazz.newInstance());
143-
scheduledJobs.add(job);
139+
Job<?> job = createJob(clazz);
144140
// start running job now in the background
145141
@SuppressWarnings("unchecked")
146142
Callable<Job> callable = (Callable<Job>) job;
@@ -156,8 +152,7 @@ public void afterApplicationStart() {
156152
// @On
157153
if (clazz.isAnnotationPresent(On.class)) {
158154
try {
159-
Job<?> job = ((Job<?>) clazz.newInstance());
160-
scheduledJobs.add(job);
155+
Job<?> job = createJob(clazz);
161156
scheduleForCRON(job);
162157
} catch (InstantiationException ex) {
163158
throw new UnexpectedException("Cannot instanciate Job " + clazz.getName());
@@ -168,8 +163,7 @@ public void afterApplicationStart() {
168163
// @Every
169164
if (clazz.isAnnotationPresent(Every.class)) {
170165
try {
171-
Job job = (Job) clazz.newInstance();
172-
scheduledJobs.add(job);
166+
Job job = createJob(clazz);
173167
String value = job.getClass().getAnnotation(Every.class).value();
174168
if (value.startsWith("cron.")) {
175169
value = Play.configuration.getProperty(value);
@@ -187,10 +181,17 @@ public void afterApplicationStart() {
187181
}
188182
}
189183

184+
private Job<?> createJob(Class<?> clazz) throws InstantiationException, IllegalAccessException {
185+
Job<?> job = (Job<?>) clazz.newInstance();
186+
scheduledJobs.add(job);
187+
return job;
188+
}
189+
190190
@Override
191191
public void onApplicationStart() {
192192
int core = Integer.parseInt(Play.configuration.getProperty("play.jobs.pool", "10"));
193193
executor = new ScheduledThreadPoolExecutor(core, new PThreadFactory("jobs"), new ThreadPoolExecutor.AbortPolicy());
194+
scheduledJobs = new ArrayList<Job>();
194195
}
195196

196197
public static <V> void scheduleForCRON(Job<V> job) {
@@ -202,7 +203,7 @@ public static <V> void scheduleForCRON(Job<V> job) {
202203
cron = Play.configuration.getProperty(cron);
203204
}
204205
cron = Expression.evaluate(cron, cron).toString();
205-
if (cron == null || "".equals(cron) || "never".equalsIgnoreCase(cron)) {
206+
if (cron == null || cron.isEmpty() || "never".equalsIgnoreCase(cron)) {
206207
Logger.info("Skipping job %s, cron expression is not defined", job.getClass().getName());
207208
return;
208209
}
@@ -212,8 +213,8 @@ public static <V> void scheduleForCRON(Job<V> job) {
212213
CronExpression cronExp = new CronExpression(cron);
213214
Date nextDate = cronExp.getNextValidTimeAfter(now);
214215
if (nextDate == null) {
215-
Logger.warn("The cron expression for job %s doesn't have any match in the future, will never be executed", job.getClass()
216-
.getName());
216+
Logger.warn("The cron expression for job %s doesn't have any match in the future, will never be executed",
217+
job.getClass().getName());
217218
return;
218219
}
219220
if (nextDate.equals(job.nextPlannedExecution)) {
@@ -240,8 +241,7 @@ public void onApplicationStop() {
240241
// @OnApplicationStop
241242
if (clazz.isAnnotationPresent(OnApplicationStop.class)) {
242243
try {
243-
Job<?> job = ((Job<?>) clazz.newInstance());
244-
scheduledJobs.add(job);
244+
Job<?> job = createJob(clazz);
245245
job.run();
246246
if (job.wasError) {
247247
if (job.lastException != null) {
@@ -268,20 +268,20 @@ public void onApplicationStop() {
268268

269269
@Override
270270
public void beforeInvocation() {
271-
afterInvocationActions.set(new LinkedList<Callable<? extends Object>>());
271+
afterInvocationActions.set(new LinkedList<Callable<?>>());
272272
}
273273

274274
@Override
275275
public void afterInvocation() {
276-
List<Callable<? extends Object>> currentActions = afterInvocationActions.get();
276+
List<Callable<?>> currentActions = afterInvocationActions.get();
277277
afterInvocationActions.set(null);
278-
for (Callable<? extends Object> callable : currentActions) {
279-
JobsPlugin.executor.submit(callable);
278+
for (Callable<?> callable : currentActions) {
279+
executor.submit(callable);
280280
}
281281
}
282282

283283
// default visibility, because we want to use this only from Job.java
284-
static void addAfterRequestAction(Callable<? extends Object> c) {
284+
static void addAfterRequestAction(Callable<?> c) {
285285
if (Request.current() == null) {
286286
throw new IllegalStateException("After request actions can be added only from threads that serve requests!");
287287
}

0 commit comments

Comments
 (0)