| borgbutler-core/src/main/java/de/micromata/borgbutler/BorgQueueExecutor.java | ●●●●● patch | view | raw | blame | history | |
| borgbutler-core/src/main/java/de/micromata/borgbutler/BorgQueueStatistics.java | ●●●●● patch | view | raw | blame | history | |
| borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/JobQueue.java | ●●●●● patch | view | raw | blame | history | |
| borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java | ●●●●● patch | view | raw | blame | history | |
| borgbutler-webapp/src/containers/WebApp.jsx | ●●●●● patch | view | raw | blame | history |
borgbutler-core/src/main/java/de/micromata/borgbutler/BorgQueueExecutor.java
@@ -15,6 +15,7 @@ public class BorgQueueExecutor { private Logger log = LoggerFactory.getLogger(BorgQueueExecutor.class); private static final BorgQueueExecutor instance = new BorgQueueExecutor(); private static final String NONE_REPO_QUEUE = "--NO_REPO--"; public static BorgQueueExecutor getInstance() { return instance; @@ -23,6 +24,25 @@ // key is the repo name. private Map<String, JobQueue<String>> queueMap = new HashMap<>(); public BorgQueueStatistics getStatistics() { BorgQueueStatistics statistics = new BorgQueueStatistics(); Iterator<JobQueue<String>> it = queueMap.values().iterator(); while (it.hasNext()) { JobQueue<?> queue = it.next(); statistics.totalNumberOfQueues++; int queueSize = queue.getQueueSize(); if (queueSize > 0) { statistics.numberOfActiveQueues++; statistics.numberOfRunningAndQueuedJobs += queueSize; } int oldJobsSize = queue.getOldJobsSize(); if (oldJobsSize > 0) { statistics.numberOfOldJobs += oldJobsSize; } } return statistics; } /** * @return A list of all repos with queues. */ @@ -98,7 +118,7 @@ } private String getQueueName(BorgRepoConfig repoConfig) { return repoConfig != null ? repoConfig.getId() : "--NO_REPO--"; return repoConfig != null ? repoConfig.getId() : NONE_REPO_QUEUE; } public BorgJob<Void> execute(BorgCommand command) { borgbutler-core/src/main/java/de/micromata/borgbutler/BorgQueueStatistics.java
New file @@ -0,0 +1,19 @@ package de.micromata.borgbutler; import lombok.Getter; /** * Statistics of all the job queues, especially the number of total queued and running jobs. * This is used e. g. by the client for showing a badge near to the menu entry "job monitor" with the number * of Jobs in the queues. */ public class BorgQueueStatistics { @Getter int numberOfRunningAndQueuedJobs = 0; @Getter int numberOfOldJobs = 0; @Getter int numberOfActiveQueues = 0; @Getter int totalNumberOfQueues = 0; } borgbutler-core/src/main/java/de/micromata/borgbutler/jobs/JobQueue.java
@@ -9,21 +9,34 @@ import java.util.concurrent.Executors; public class JobQueue<T> { private static final int MAX_DONE_JOBS_SIZE = 50; private static final int MAX_OLD_JOBS_SIZE = 50; private static long jobSequence = 0; private Logger log = LoggerFactory.getLogger(JobQueue.class); private List<AbstractJob<T>> queue = new ArrayList<>(); private List<AbstractJob<T>> doneJobs = new LinkedList<>(); /** * Finished, failed and cancelled jobs. */ private List<AbstractJob<T>> oldJobs = new LinkedList<>(); private ExecutorService executorService = Executors.newSingleThreadExecutor(); private static synchronized void setNextJobId(AbstractJob<?> job) { job.setUniqueJobNumber(jobSequence++); } /** * @return the number of running and queued jobs of this queue or 0 if no job is in the queue. */ public int getQueueSize() { return queue.size(); } /** * @return the number of old jobs (done, failed or cancelled) stored. The size of stored old jobs is limited. */ public int getOldJobsSize() { return oldJobs.size(); } public Iterator<AbstractJob<T>> getQueueIterator() { return Collections.unmodifiableList(queue).iterator(); } @@ -93,13 +106,13 @@ AbstractJob<T> job = it.next(); if (job.isFinished()) { it.remove(); synchronized (doneJobs) { doneJobs.add(0, job); synchronized (oldJobs) { oldJobs.add(0, job); } } synchronized (doneJobs) { while (doneJobs.size() > MAX_DONE_JOBS_SIZE) { doneJobs.remove(doneJobs.size() - 1); synchronized (oldJobs) { while (oldJobs.size() > MAX_OLD_JOBS_SIZE) { oldJobs.remove(oldJobs.size() - 1); } } } borgbutler-server/src/main/java/de/micromata/borgbutler/server/rest/JobsRest.java
@@ -66,6 +66,17 @@ return JsonUtils.toJson(queueList, prettyPrinter); } @GET @Produces(MediaType.APPLICATION_JSON) @Path("/statistics") /** * @return The total number of jobs queued or running (and other statistics): {@link de.micromata.borgbutler.BorgQueueStatistics}. * @see JsonUtils#toJson(Object, boolean) */ public String getStatistics() { return JsonUtils.toJson(BorgQueueExecutor.getInstance().getStatistics()); } private JsonJobQueue getQueue(String repo) { BorgQueueExecutor borgQueueExecutor = BorgQueueExecutor.getInstance(); BorgRepoConfig repoConfig = ConfigurationHandler.getConfiguration().getRepoConfig(repo); borgbutler-webapp/src/containers/WebApp.jsx
@@ -2,6 +2,7 @@ import createBrowserHistory from 'history/createBrowserHistory'; import {Route, Router, Switch} from 'react-router'; import {connect} from 'react-redux'; import {Badge} from 'reactstrap'; import Menu from '../components/general/Menu'; import Start from '../components/views/Start'; @@ -11,7 +12,7 @@ import ConfigurationPage from '../components/views/config/ConfigurationPage'; import RestServices from '../components/views/develop/RestServices'; import JobMonitorView from '../components/views/jobs/JobMonitorView'; import {isDevelopmentMode} from '../utilities/global'; import {getRestServiceUrl, isDevelopmentMode} from '../utilities/global'; import LogPage from '../components/views/logging/LogPage'; import Footer from '../components/views/footer/Footer'; import {loadVersion} from '../actions'; @@ -23,13 +24,34 @@ componentDidMount = () => { this.props.loadVersion(); this.interval = setInterval(() => this.fetchJobStatistics(), 5000); }; fetchJobStatistics = () => { fetch(getRestServiceUrl('jobs/statistics'), { method: 'GET', headers: { 'Accept': 'application/json' } }) .then(response => response.json()) .then(json => { this.setState({ statistics: json }); }) .catch(); }; render() { let jobsBadge = ''; if (this.state && this.state.statistics && this.state.statistics.numberOfRunningAndQueuedJobs > 0) { jobsBadge = <Badge color="danger" pill>{this.state.statistics.numberOfRunningAndQueuedJobs}</Badge>; } let routes = [ ['Start', '/', Start], ['Repositories', '/repos', RepoListView], ['Job monitor', '/jobmonitor', JobMonitorView], ['Job monitor', '/jobmonitor', JobMonitorView, {badge: jobsBadge}], [getTranslation('logviewer'), '/logging', LogPage], [getTranslation('configuration'), '/config', ConfigurationPage] ];