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

de.otto.jlineup.service.JLineupService Maven / Gradle / Ivy

package de.otto.jlineup.service;

import com.google.common.collect.ImmutableList;
import de.otto.jlineup.GlobalOption;
import de.otto.jlineup.GlobalOptions;
import de.otto.jlineup.JLineupRunner;
import de.otto.jlineup.config.JobConfig;
import de.otto.jlineup.web.JLineupRunStatus;
import de.otto.jlineup.web.JLineupRunnerFactory;
import de.otto.jlineup.web.State;
import de.otto.jlineup.web.configuration.JLineupWebProperties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.time.Instant;
import java.util.List;
import java.util.Optional;
import java.util.UUID;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

import static de.otto.jlineup.web.JLineupRunStatus.copyOfRunStatusBuilder;
import static de.otto.jlineup.web.JLineupRunStatus.runStatusBuilder;
import static java.lang.invoke.MethodHandles.lookup;
import static java.util.concurrent.CompletableFuture.supplyAsync;

@Service
public class JLineupService {

    private final static Logger LOG = LoggerFactory.getLogger(lookup().lookupClass());

    private final ConcurrentHashMap runs = new ConcurrentHashMap<>();
    private final ExecutorService executorService;
    private final AtomicInteger runningJobs = new AtomicInteger();

    private final JLineupRunnerFactory jLineupRunnerFactory;
    private final JLineupWebProperties jLineupWebProperties;
    private final RunPersistenceService runPersistenceService;

    @Autowired
    public JLineupService(JLineupRunnerFactory jLineupRunnerFactory,
                          JLineupWebProperties jLineupWebProperties,
                          RunPersistenceService runPersistenceService) {
        this.jLineupRunnerFactory = jLineupRunnerFactory;
        this.jLineupWebProperties = jLineupWebProperties;
        this.runPersistenceService = runPersistenceService;
        this.executorService = Executors.newFixedThreadPool(jLineupWebProperties.getMaxParallelJobs());
        this.runs.putAll(runPersistenceService.readRuns());

        GlobalOptions.setOption(GlobalOption.JLINEUP_LAMBDA_FUNCTION_NAME, jLineupWebProperties.getLambda().getFunctionName());
    }

    public synchronized JLineupRunStatus startBeforeRun(JobConfig jobConfig) throws Exception {
        String runId = UUID.randomUUID().toString();
        final JLineupRunStatus beforeStatus = runStatusBuilder()
                .withId(runId)
                .withJobConfig(jobConfig)
                .withState(State.BEFORE_PENDING)
                .withStartTime(Instant.now())
                .build();

        final JLineupRunner jLineupRunner = jLineupRunnerFactory.createBeforeRun(runId, jobConfig);
        runs.put(runId, beforeStatus);
        runPersistenceService.persistRuns(runs);

        runningJobs.incrementAndGet();

        CompletableFuture state = supplyAsync(
                () -> {
                    changeState(runId, State.BEFORE_RUNNING);
                    jLineupRunner.run();
                    return State.BEFORE_DONE;
                }, executorService)
                .exceptionally(ex -> {
                    LOG.error("Error in before runStep.", ex);
                    return State.ERROR;
                })
                .thenApply(st -> {
                    changeState(runId, st);
                    runningJobs.decrementAndGet();
                    return st;
                });

        return JLineupRunStatus.copyOfRunStatusBuilder(beforeStatus).withCurrentJobStepFuture(state).build();
    }

    public synchronized JLineupRunStatus startAfterRun(String runId) throws Exception {

        Optional run = getRun(runId);
        if (run.isEmpty()) {
            throw new RunNotFoundException(runId);
        }

        JLineupRunStatus beforeStatus = run.get();
        if (beforeStatus.getState() != State.BEFORE_DONE) {
            throw new InvalidRunStateException(beforeStatus.getId(), beforeStatus.getState(), State.BEFORE_DONE);
        }

        final JLineupRunner jLineupRunner = jLineupRunnerFactory.createAfterRun(runId, beforeStatus.getJobConfig());
        JLineupRunStatus afterStatus = changeState(runId, State.AFTER_PENDING);
        runningJobs.incrementAndGet();

        CompletableFuture state = supplyAsync(
                () -> {
                    changeState(runId, State.AFTER_RUNNING);
                    boolean runSucceeded = jLineupRunner.run();
                    if (runSucceeded) {
                        return State.FINISHED_WITHOUT_DIFFERENCES;
                    } else {
                        return State.FINISHED_WITH_DIFFERENCES;
                    }
                }, executorService)
                .exceptionally(ex -> {
                    LOG.error("Error in after runStep.", ex);
                    return State.ERROR;
                })
                .thenApply(st -> {
                    changeState(runId, st);
                    runningJobs.decrementAndGet();
                    return st;
                });

        return JLineupRunStatus.copyOfRunStatusBuilder(afterStatus).withCurrentJobStepFuture(state).build();
    }

    private JLineupRunStatus changeState(String runId, State state) {
        JLineupRunStatus runStatus = runs.get(runId);
        JLineupRunStatus.Builder runStatusBuilder = copyOfRunStatusBuilder(runStatus).withState(state);

        if (state == State.BEFORE_RUNNING) {
            runStatusBuilder.withReports(JLineupRunStatus.Reports.reportsBuilder()
                    .withLogUrl("/reports/report-" + runId + "/jlineup.log")
                    .build());
        }

        if (state == State.BEFORE_DONE) {
            runStatusBuilder.withPauseTime(Instant.now());
        }

        if (state == State.AFTER_RUNNING) {
            runStatusBuilder.withResumeTime(Instant.now());
        }

        if (state == State.ERROR || state == State.DEAD) {
            runStatusBuilder.withEndTime(Instant.now());
        }

        if (state == State.FINISHED_WITH_DIFFERENCES
                || state == State.FINISHED_WITHOUT_DIFFERENCES) {
            runStatusBuilder.withEndTime(Instant.now());
            runStatusBuilder.withReports(JLineupRunStatus.Reports.reportsBuilder()
                    .withHtmlUrl("/reports/report-" + runId + "/report.html")
                    .withJsonUrl("/reports/report-" + runId + "/report.json")
                    .withLogUrl("/reports/report-" + runId + "/jlineup.log")
                    .build());
        }

        JLineupRunStatus newStatus = runStatusBuilder.build();
        runs.put(runId, newStatus);
        runPersistenceService.persistRuns(runs);
        return newStatus;
    }



    public Optional getRun(String id) {
        return Optional.ofNullable(runs.get(id));
    }

    public List getRunStatus() {
        return ImmutableList.copyOf(this.runs.values());
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy