All Downloads are FREE. Search and download functionalities are using the official Maven repository.

play.jobs.Job Maven / Gradle / Ivy

There is a newer version: 2.6.2
Show newest version
package play.jobs;

import com.jamonapi.Monitor;
import com.jamonapi.MonitorFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import play.Invocation;
import play.InvocationContext;
import play.Play;
import play.db.jpa.JPA;
import play.exceptions.PlayException;
import play.exceptions.UnexpectedException;
import play.libs.Promise;
import play.libs.Time;

import java.util.Date;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.TimeUnit;

/**
 * A job is an asynchronously executed unit of work
 * 
 * @param 
 *            The job result type (if any)
 */
public abstract class Job extends Invocation implements Callable {
    private static final Logger logger = LoggerFactory.getLogger(Job.class);

    public static final String invocationType = "Job";

    protected ExecutorService executor;
    protected long lastRun;
    protected boolean wasError;
    protected Throwable lastException;
    boolean runOnce;

    Date nextPlannedExecution;

    @Override
    public InvocationContext getInvocationContext() {
        return new InvocationContext(invocationType, this.getClass().getAnnotations());
    }

    /**
     * Here you do the job and return a result
     * 
     * @return The job result
     */
    public abstract V doJobWithResult() throws Exception;

    @Override
    public void execute() {
    }

    /**
     * Start this job now (well ASAP)
     * 
     * @return the job completion
     */
    public Promise now() {
        Promise smartFuture = new Promise<>();
        JobsPlugin.executor.submit(getJobCallingCallable(smartFuture));
        return smartFuture;
    }

    /**
     * Start this job in several seconds
     * 
     * @param delay
     *            time in seconds
     * @return the job completion
     */
    public Promise in(String delay) {
        return in(Time.parseDuration(delay));
    }

    /**
     * Start this job in several seconds
     * 
     * @param seconds
     *            time in seconds
     * @return the job completion
     */
    public Promise in(int seconds) {
        Promise smartFuture = new Promise<>();
        JobsPlugin.executor.schedule(getJobCallingCallable(smartFuture), seconds, TimeUnit.SECONDS);
        return smartFuture;
    }

    private Callable getJobCallingCallable(final Promise smartFuture) {
        return () -> {
            try {
                V result = this.call();
                if (smartFuture != null) {
                    smartFuture.accept(result);
                }
                return result;
            } catch (Exception e) {
                if (smartFuture != null) {
                    smartFuture.invokeWithException(e);
                }
                return null;
            }
        };
    }

    /**
     * Run this job every n seconds
     * 
     * @param delay
     *            time in seconds
     */
    public void every(String delay) {
        every(Time.parseDuration(delay));
    }

    /**
     * Run this job every n seconds
     * 
     * @param seconds
     *            time in seconds
     */
    public void every(int seconds) {
        JobsPlugin.executor.scheduleWithFixedDelay(this, seconds, seconds, TimeUnit.SECONDS);
        JobsPlugin.scheduledJobs.add(this);
    }

    private void onJobInvocationException(Throwable e) {
        wasError = true;
        lastException = e;
        try {
            logger.error("Unexpected exception in job {}", this, e);
            Play.pluginCollection.onJobInvocationException(e);
        } catch (Throwable ex) {
            logger.error("Error during job exception handling ({})", this, ex);
            throw new UnexpectedException(unwrap(e));
        }
    }

    private Throwable unwrap(Throwable e) {
        while ((e instanceof UnexpectedException || e instanceof PlayException) && e.getCause() != null) {
            e = e.getCause();
        }
        return e;
    }

    @Override
    public void run() {
        call();
    }

    @Override
    public V call() {
        Monitor monitor = null;
        try {
            if (init()) {
                before();
                lastException = null;
                lastRun = System.currentTimeMillis();
                monitor = MonitorFactory.start(this + ".doJob()");
                V result = JPA.withinFilter(() -> doJobWithResult());
                monitor.stop();
                monitor = null;
                wasError = false;
                after();
                return result;
            }
        } catch (Throwable e) {
            onJobInvocationException(e);
        } finally {
            if (monitor != null) {
                monitor.stop();
            }
            _finally();
        }
        return null;
    }

    protected void _finally() {
      Play.pluginCollection.onJobInvocationFinally();
      InvocationContext.current.remove();

      synchronized (this) {
            try {
                if (executor == JobsPlugin.executor && !runOnce) {
                    JobsPlugin.scheduleForCRON(this);
                }
            }
            finally {
                runOnce = false;
            }
        }
    }

    @Override
    public String toString() {
        return this.getClass().getName();
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy