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

net.scattersphere.util.thread.JobManager Maven / Gradle / Ivy

The newest version!
/*
 * Scattersphere
 * Copyright 2014-2015, Scattersphere Project.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *       http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package net.scattersphere.util.thread;

import net.scattersphere.job.AbstractJob;
import net.scattersphere.job.Job;
import net.scattersphere.server.Main;
import net.scattersphere.util.PropertyUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * This class handles the queueing of jobs to start.  Jobs are automatically passed on to the next available
 * {@link JobManagerQueueExecutor} in sequential order.  Any queues that do not have an available thread will queue the job
 * until the {@link Thread} frees up.
 *
 * @author [email protected]
 */
public class JobManager {

    private static final JobManager instance = new JobManager();

	private final List knownExecutors;
    private final AtomicInteger currentExecutorPosition;

    private final Logger LOG = LoggerFactory.getLogger(JobManager.class);

    private JobManager() {
        int threadsAvailable = Runtime.getRuntime().availableProcessors();

        LOG.info("*** Threads available: {}", threadsAvailable);

        /*
         * TODO: Is there a better way to manage this??
         */
        knownExecutors = new ArrayList<>();

        int maxThreads = Integer.parseInt(PropertyUtil.get("server.threads.max", Main.serverProperties, "" + threadsAvailable));

        if (maxThreads <= 0) {
            maxThreads = threadsAvailable;
            System.err.println("*** WARNING: \"server.threads.max\" improperly set.  Using max=" + threadsAvailable);
        } else if (maxThreads > threadsAvailable) {
            System.err.println("*** WARNING: \"server.threads.max\" property set higher than threads available.  Requested=" + maxThreads +
                " Available=" + threadsAvailable);
        } else if (maxThreads != threadsAvailable) {
            LOG.info("--- Max threads adjusted: max={}", maxThreads);
            threadsAvailable = maxThreads;
        }

		for(int i = 0; i < threadsAvailable; i++) {
			JobManagerQueueExecutor jmqExecutor = new JobManagerQueueExecutor("Job Manager Executor - Managed Thread Controller #" + (i + 1));

			knownExecutors.add(jmqExecutor);

			jmqExecutor.start();
		}

        currentExecutorPosition = new AtomicInteger(0);
    }

    /**
     * Retrieves the default instance.
     *
     * @return {@link JobManager} default instance.
     */
    public static JobManager instance() {
        return instance;
    }

    /**
     * Queues a job to start, passing in additional arguments to run.
     *
     * @param job The {@link Job} to run.
     * @param jobName The name of the job.
     * @param arguments {@code String[]} containing the list of arguments to pass to the job.
     * @return {@code String} containing the job ID.
     */
    public String queue(Job job, String jobName, String[] arguments) {
        int queuePosition = currentExecutorPosition.incrementAndGet();

        if (queuePosition >= knownExecutors.size()) {
            queuePosition = 0;
            currentExecutorPosition.set(0);
        }

        JobManagerQueueExecutor executor = knownExecutors.get(queuePosition);
        JobExecutionContext context = new JobExecutionContext(job, jobName, arguments);

        // Assign the job ID here to the job.
        if (job instanceof AbstractJob) {
            AbstractJob aJob = (AbstractJob) job;

            aJob.setJobId(context.getJobContext().getJobId());
        }

        executor.queue(context);

        return context.getJobContext().getJobId();
    }

    /**
     * Stops a job by ID.
     *
     * @param jobId The UUID of the job to stop.
     * @param reason The reason to stop the job.
     * @return {@code true} if the job was stopped or dequeued, {@code false} otherwise.
     */
    public boolean stop(String jobId, String reason) {
        // TODO: Lambda

        for(JobManagerQueueExecutor exec : knownExecutors) {
            if (exec.stop(jobId, reason)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Retrieves the status of a job by ID.
     *
     * @param jobId The Job ID to look up.
     * @return {@code String} containing the status, {@code NOT FOUND} if not found.
     */
    public String status(String jobId) {
        // TODO: Lambda

        for(JobManagerQueueExecutor exec : knownExecutors) {
            if (exec.isQueued(jobId)) {
                return JobExecutionResult.QUEUED.toString();
            }
        }

        JobExecutionContext context = JobManagerCache.instance().findJobStatus(jobId);

        if (context != null) {
            return context.getJobContext().getJobResult().toString();
        }

        return "NOT FOUND";
    }

    /**
     * Retrieves a list of queued jobs.
     *
     * @return {@link List} of {code String}s of job IDs.
     */
    public List getQueuedJobs() {
        List returnList = new ArrayList<>();

        // TODO: Lambda

        for(JobManagerQueueExecutor exec : knownExecutors) {
            returnList.addAll(exec.getQueuedJobs());
        }

        return returnList;
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy