@Override public void onApplicationStop() { List<Class> jobs = Play.classloader.getAssignableClasses(Job.class); for (final Class clazz : jobs) { // @OnApplicationStop if (clazz.isAnnotationPresent(OnApplicationStop.class)) { try { Job<?> job = ((Job<?>) clazz.newInstance()); scheduledJobs.add(job); job.run(); if (job.wasError) { if (job.lastException != null) { throw job.lastException; } throw new RuntimeException("@OnApplicationStop Job has failed"); } } catch (InstantiationException e) { throw new UnexpectedException("Job could not be instantiated", e); } catch (IllegalAccessException e) { throw new UnexpectedException("Job could not be instantiated", e); } catch (Throwable ex) { if (ex instanceof PlayException) { throw (PlayException) ex; } throw new UnexpectedException(ex); } } } executor.shutdownNow(); executor.getQueue().clear(); }
static void realMain(String[] args) throws Throwable { // jmap doesn't work on Windows if (System.getProperty("os.name").startsWith("Windows")) return; final String childClassName = Job.class.getName(); final String classToCheckForLeaks = Job.classToCheckForLeaks(); final String uniqueID = String.valueOf(new Random().nextInt(Integer.MAX_VALUE)); final String[] jobCmd = { java, "-Xmx8m", "-classpath", System.getProperty("test.classes", "."), childClassName, uniqueID }; final Process p = new ProcessBuilder(jobCmd).start(); final String childPid = match( commandOutputOf(jps, "-m"), "(?m)^ *([0-9]+) +\\Q" + childClassName + "\\E *" + uniqueID + "$", 1); final int n0 = objectsInUse(p, childPid, classToCheckForLeaks); final int n1 = objectsInUse(p, childPid, classToCheckForLeaks); equal(p.waitFor(), 0); equal(p.exitValue(), 0); failed += p.exitValue(); // Check that no objects were leaked. System.out.printf("%d -> %d%n", n0, n1); check(Math.abs(n1 - n0) < 2); // Almost always n0 == n1 check(n1 < 20); drainers.shutdown(); }
public static <V> void scheduleForCRON(Job<V> job) { if (!job.getClass().isAnnotationPresent(On.class)) { return; } String cron = job.getClass().getAnnotation(On.class).value(); if (cron.startsWith("cron.")) { cron = Play.configuration.getProperty(cron); } cron = Expression.evaluate(cron, cron).toString(); if (cron == null || "".equals(cron) || "never".equalsIgnoreCase(cron)) { Logger.info("Skipping job %s, cron expression is not defined", job.getClass().getName()); return; } try { Date now = new Date(); cron = Expression.evaluate(cron, cron).toString(); CronExpression cronExp = new CronExpression(cron); Date nextDate = cronExp.getNextValidTimeAfter(now); if (nextDate == null) { Logger.warn( "The cron expression for job %s doesn't have any match in the future, will never be executed", job.getClass().getName()); return; } if (nextDate.equals(job.nextPlannedExecution)) { // Bug #13: avoid running the job twice for the same time // (happens when we end up running the job a few minutes before the planned time) Date nextInvalid = cronExp.getNextInvalidTimeAfter(nextDate); nextDate = cronExp.getNextValidTimeAfter(nextInvalid); } job.nextPlannedExecution = nextDate; executor.schedule( (Callable<V>) job, nextDate.getTime() - now.getTime(), TimeUnit.MILLISECONDS); job.executor = executor; } catch (Exception ex) { throw new UnexpectedException(ex); } }
@Override public String getStatus() { StringWriter sw = new StringWriter(); PrintWriter out = new PrintWriter(sw); if (executor == null) { out.println("Jobs execution pool:"); out.println("~~~~~~~~~~~~~~~~~~~"); out.println("(not yet started)"); return sw.toString(); } out.println("Jobs execution pool:"); out.println("~~~~~~~~~~~~~~~~~~~"); out.println("Pool size: " + executor.getPoolSize()); out.println("Active count: " + executor.getActiveCount()); out.println("Scheduled task count: " + executor.getTaskCount()); out.println("Queue size: " + executor.getQueue().size()); SimpleDateFormat df = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss"); if (!scheduledJobs.isEmpty()) { out.println(); out.println("Scheduled jobs (" + scheduledJobs.size() + "):"); out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~"); for (Job job : scheduledJobs) { out.print(job.getClass().getName()); if (job.getClass().isAnnotationPresent(OnApplicationStart.class) && !(job.getClass().isAnnotationPresent(On.class) || job.getClass().isAnnotationPresent(Every.class))) { OnApplicationStart appStartAnnotation = job.getClass().getAnnotation(OnApplicationStart.class); out.print( " run at application start" + (appStartAnnotation.async() ? " (async)" : "") + "."); } if (job.getClass().isAnnotationPresent(On.class)) { String cron = job.getClass().getAnnotation(On.class).value(); if (cron != null && cron.startsWith("cron.")) { cron = Play.configuration.getProperty(cron); } out.print(" run with cron expression " + cron + "."); } if (job.getClass().isAnnotationPresent(Every.class)) { out.print(" run every " + job.getClass().getAnnotation(Every.class).value() + "."); } if (job.lastRun > 0) { out.print(" (last run at " + df.format(new Date(job.lastRun))); if (job.wasError) { out.print(" with error)"); } else { out.print(")"); } } else { out.print(" (has never run)"); } out.println(); } } if (!executor.getQueue().isEmpty()) { out.println(); out.println("Waiting jobs:"); out.println("~~~~~~~~~~~~~~~~~~~~~~~~~~~"); ScheduledFuture[] q = executor.getQueue().toArray(new ScheduledFuture[0]); for (int i = 0; i < q.length; i++) { ScheduledFuture task = q[i]; out.println( Java.extractUnderlyingCallable((FutureTask<?>) task) + " will run in " + task.getDelay(TimeUnit.SECONDS) + " seconds"); } } return sw.toString(); }
@Override public void afterApplicationStart() { List<Class<?>> jobs = new ArrayList<Class<?>>(); for (Class clazz : Play.classloader.getAllClasses()) { if (Job.class.isAssignableFrom(clazz)) { jobs.add(clazz); } } scheduledJobs = new ArrayList<Job>(); for (final Class<?> clazz : jobs) { // @OnApplicationStart if (clazz.isAnnotationPresent(OnApplicationStart.class)) { // check if we're going to run the job sync or async OnApplicationStart appStartAnnotation = clazz.getAnnotation(OnApplicationStart.class); if (!appStartAnnotation.async()) { // run job sync try { Job<?> job = ((Job<?>) clazz.newInstance()); scheduledJobs.add(job); job.run(); if (job.wasError) { if (job.lastException != null) { throw job.lastException; } throw new RuntimeException("@OnApplicationStart Job has failed"); } } catch (InstantiationException e) { throw new UnexpectedException("Job could not be instantiated", e); } catch (IllegalAccessException e) { throw new UnexpectedException("Job could not be instantiated", e); } catch (Throwable ex) { if (ex instanceof PlayException) { throw (PlayException) ex; } throw new UnexpectedException(ex); } } else { // run job async try { Job<?> job = ((Job<?>) clazz.newInstance()); scheduledJobs.add(job); // start running job now in the background @SuppressWarnings("unchecked") Callable<Job> callable = (Callable<Job>) job; executor.submit(callable); } catch (InstantiationException ex) { throw new UnexpectedException("Cannot instanciate Job " + clazz.getName()); } catch (IllegalAccessException ex) { throw new UnexpectedException("Cannot instanciate Job " + clazz.getName()); } } } // @On if (clazz.isAnnotationPresent(On.class)) { try { Job<?> job = ((Job<?>) clazz.newInstance()); scheduledJobs.add(job); scheduleForCRON(job); } catch (InstantiationException ex) { throw new UnexpectedException("Cannot instanciate Job " + clazz.getName()); } catch (IllegalAccessException ex) { throw new UnexpectedException("Cannot instanciate Job " + clazz.getName()); } } // @Every if (clazz.isAnnotationPresent(Every.class)) { try { Job job = (Job) clazz.newInstance(); scheduledJobs.add(job); String value = job.getClass().getAnnotation(Every.class).value(); if (value.startsWith("cron.")) { value = Play.configuration.getProperty(value); } value = Expression.evaluate(value, value).toString(); if (!"never".equalsIgnoreCase(value)) { executor.scheduleWithFixedDelay( job, Time.parseDuration(value), Time.parseDuration(value), TimeUnit.SECONDS); } } catch (InstantiationException ex) { throw new UnexpectedException("Cannot instanciate Job " + clazz.getName()); } catch (IllegalAccessException ex) { throw new UnexpectedException("Cannot instanciate Job " + clazz.getName()); } } } }