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

com.turbospaces.quartz.AbstractJob Maven / Gradle / Ivy

There is a newer version: 2.0.33
Show newest version
package com.turbospaces.quartz;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Objects;
import java.util.concurrent.TimeUnit;
import java.util.function.Supplier;

import org.apache.commons.lang3.time.StopWatch;
import org.quartz.Job;
import org.quartz.JobDataMap;
import org.quartz.JobExecutionContext;
import org.quartz.JobExecutionException;
import org.quartz.SchedulerException;
import org.slf4j.MDC;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanInitializationException;
import org.springframework.boot.ApplicationArguments;
import org.springframework.boot.ApplicationRunner;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.support.GenericApplicationContext;

import com.netflix.archaius.api.Property;
import com.turbospaces.cfg.ApplicationProperties;

import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import io.micrometer.core.instrument.Timer;
import lombok.extern.slf4j.Slf4j;

@Slf4j
public abstract class AbstractJob implements Job, ApplicationRunner, ApplicationContextAware {
    private final ApplicationProperties props;

    protected final MeterRegistry meterRegistry;
    protected String schedulerName;
    protected String schedulerInstanceId;
    protected String fireInstanceId;
    protected String threadName;
    protected JobDataMap jobDataMap;
    protected List tags = new ArrayList<>();
    protected GenericApplicationContext applicationContext;
    protected Class jobClass;
    protected StopWatch stopWatch;

    protected AbstractJob(ApplicationProperties props, MeterRegistry meterRegistry) {
        this.props = Objects.requireNonNull(props);
        this.meterRegistry = Objects.requireNonNull(meterRegistry);
    }
    @Override
    public void run(ApplicationArguments args) throws Exception {
        if (this instanceof ScheduledJob) {
            Supplier enabled = ((ScheduledJob) this).isEnabled();
            //
            // ~ in 'DEV' mode obviously
            //
            if (props.isDevMode()) {
                //
                // ~ locally we have to have way not to validate
                //
                if (props.QUARTZ_ENFORCE_DISABLED_JOBS_ENABLED.get()) {
                    if (enabled.get()) {
                        if (enabled instanceof Property) {
                            Property prop = (Property) enabled;
                            String msg = String.format("job: %s is activated by default by prop: %s", getClass().getName(), prop.getKey());
                            throw new BeanInitializationException(msg);
                        }

                        String msg = String.format("job: %s is activated by default", getClass().getName());
                        throw new BeanInitializationException(msg);
                    }
                }
            }
            ((ScheduledJob) this).schedule();
        }
    }
    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = (GenericApplicationContext) applicationContext;
    }
    @Override
    public void execute(JobExecutionContext ctx) throws JobExecutionException {
        this.stopWatch = StopWatch.createStarted();

        try {
            this.jobDataMap = ctx.getMergedJobDataMap();
            this.jobClass = ctx.getJobDetail().getJobClass();
            this.threadName = Thread.currentThread().getName();
            this.schedulerName = ctx.getScheduler().getSchedulerName();
            this.schedulerInstanceId = ctx.getScheduler().getSchedulerInstanceId();
            this.fireInstanceId = ctx.getFireInstanceId();
        } catch (SchedulerException err) {
            throw new JobExecutionException(err);
        }

        boolean toApply = applicationContext.isRunning();
        if (toApply) {
            if (this instanceof ScheduledJob) {
                //
                // ~ only locally
                //
                if (props.isDevMode()) {
                    if (Objects.nonNull(ctx.getTrigger())) {
                        Date nextFire = ctx.getTrigger().getNextFireTime(); // ~ scheduled permanently
                        if (Objects.nonNull(nextFire)) {
                            Supplier enabled = ((ScheduledJob) this).isEnabled();
                            toApply = enabled.get();
                        }
                    }
                } else {
                    Supplier enabled = ((ScheduledJob) this).isEnabled();
                    toApply = enabled.get();
                }
            }

            if (toApply) {
                try {
                    doBeforeExecution(ctx);
                    doExecute(ctx);
                } catch (Throwable err) {
                    doOnFailure(ctx, err);
                } finally {
                    stopWatch.stop();
                    Timer timer = meterRegistry.timer("job", tags);

                    log.debug("job=({}) completed in {}", getClass().getSimpleName(), stopWatch);
                    timer.record(stopWatch.getTime(), TimeUnit.MILLISECONDS);

                    MDC.clear();
                    Thread.currentThread().setName(threadName);

                    tags.clear();

                    try {
                        doAfterExecution(ctx);
                    } catch (Throwable err) {
                        log.error(err.getMessage(), err);
                    }
                }
            }
        }
    }
    protected void doBeforeExecution(JobExecutionContext ctx) throws Throwable {
        log.trace("before job execution ctx: {}", ctx);
    }
    protected void doAfterExecution(JobExecutionContext ctx) throws Throwable {
        log.trace("after job execution ctx: {}", ctx);
    }
    protected void doOnFailure(JobExecutionContext ctx, Throwable err) throws JobExecutionException {
        log.error("job finished exceptionally, dirty flag cleared now ...", err);
        throw new JobExecutionException(err);
    }
    protected abstract void doExecute(JobExecutionContext ctx) throws Throwable;
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy