Merge pull request #3777 from esaunders/3734_ingest_progress

Add ingest progress snapshot support to AID
This commit is contained in:
Richard Cordovano 2018-05-17 18:11:57 -04:00 committed by GitHub
commit 03764f0891
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
12 changed files with 260 additions and 79 deletions

View File

@ -18,6 +18,7 @@
*/
package org.sleuthkit.autopsy.ingest;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
@ -37,6 +38,9 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.ingest.DataSourceIngestPipeline.PipelineModule;
import org.sleuthkit.autopsy.ingest.IngestJob.CancellationReason;
import org.sleuthkit.autopsy.ingest.IngestTasksScheduler.IngestJobTasksSnapshot;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.IngestJobInfo;
@ -51,7 +55,7 @@ import org.sleuthkit.autopsy.modules.interestingitems.FilesSet;
* Encapsulates a data source and the ingest module pipelines used to process
* it.
*/
final class DataSourceIngestJob {
public final class DataSourceIngestJob {
private static final Logger logger = Logger.getLogger(DataSourceIngestJob.class.getName());
@ -1079,71 +1083,90 @@ final class DataSourceIngestJob {
* @return An ingest job statistics object.
*/
Snapshot getSnapshot(boolean getIngestTasksSnapshot) {
return new Snapshot(getIngestTasksSnapshot);
/**
* Determine whether file ingest is running at the time of this snapshot
* and determine the earliest file ingest level pipeline start time, if
* file ingest was started at all.
*/
boolean fileIngestRunning = false;
Date fileIngestStartTime = null;
for (FileIngestPipeline pipeline : this.fileIngestPipelines) {
if (pipeline.isRunning()) {
fileIngestRunning = true;
}
Date pipelineStartTime = pipeline.getStartTime();
if (null != pipelineStartTime && (null == fileIngestStartTime || pipelineStartTime.before(fileIngestStartTime))) {
fileIngestStartTime = pipelineStartTime;
}
}
long processedFilesCount = 0;
long estimatedFilesToProcessCount = 0;
long snapShotTime = new Date().getTime();
IngestJobTasksSnapshot tasksSnapshot = null;
if (getIngestTasksSnapshot) {
synchronized (fileIngestProgressLock) {
processedFilesCount = this.processedFiles;
estimatedFilesToProcessCount = this.estimatedFilesToProcess;
snapShotTime = new Date().getTime();
}
tasksSnapshot = DataSourceIngestJob.taskScheduler.getTasksSnapshotForJob(id);
}
return new Snapshot(this.dataSource.getName(), id, createTime,
getCurrentDataSourceIngestModule(), fileIngestRunning, fileIngestStartTime,
cancelled, cancellationReason, cancelledDataSourceIngestModules,
processedFilesCount, estimatedFilesToProcessCount, snapShotTime, tasksSnapshot);
}
/**
* Stores basic diagnostic statistics for a data source ingest job.
*/
final class Snapshot {
public static final class Snapshot implements Serializable {
private static final long serialVersionUID = 1L;
private final String dataSource;
private final long jobId;
private final long jobStartTime;
private final long snapShotTime;
private final DataSourceIngestPipeline.PipelineModule dataSourceLevelIngestModule;
private boolean fileIngestRunning;
private Date fileIngestStartTime;
transient private final PipelineModule dataSourceLevelIngestModule;
private final boolean fileIngestRunning;
private final Date fileIngestStartTime;
private final long processedFiles;
private final long estimatedFilesToProcess;
private final IngestTasksScheduler.IngestJobTasksSnapshot tasksSnapshot;
private final boolean jobCancelled;
private final IngestJob.CancellationReason jobCancellationReason;
private final List<String> cancelledDataSourceModules;
private final IngestJobTasksSnapshot tasksSnapshot;
transient private final boolean jobCancelled;
transient private final CancellationReason jobCancellationReason;
transient private final List<String> cancelledDataSourceModules;
/**
* Constructs an object to store basic diagnostic statistics for a data
* source ingest job.
*/
Snapshot(boolean getIngestTasksSnapshot) {
this.dataSource = DataSourceIngestJob.this.dataSource.getName();
this.jobId = DataSourceIngestJob.this.id;
this.jobStartTime = DataSourceIngestJob.this.createTime;
this.dataSourceLevelIngestModule = DataSourceIngestJob.this.getCurrentDataSourceIngestModule();
Snapshot(String dataSourceName, long jobId, long jobStartTime, PipelineModule dataSourceIngestModule,
boolean fileIngestRunning, Date fileIngestStartTime,
boolean jobCancelled, CancellationReason cancellationReason, List<String> cancelledModules,
long processedFiles, long estimatedFilesToProcess,
long snapshotTime, IngestJobTasksSnapshot tasksSnapshot) {
this.dataSource = dataSourceName;
this.jobId = jobId;
this.jobStartTime = jobStartTime;
this.dataSourceLevelIngestModule = dataSourceIngestModule;
/**
* Determine whether file ingest is running at the time of this
* snapshot and determine the earliest file ingest level pipeline
* start time, if file ingest was started at all.
*/
for (FileIngestPipeline pipeline : DataSourceIngestJob.this.fileIngestPipelines) {
if (pipeline.isRunning()) {
this.fileIngestRunning = true;
}
Date pipelineStartTime = pipeline.getStartTime();
if (null != pipelineStartTime && (null == this.fileIngestStartTime || pipelineStartTime.before(this.fileIngestStartTime))) {
this.fileIngestStartTime = pipelineStartTime;
}
}
this.jobCancelled = cancelled;
this.fileIngestRunning = fileIngestRunning;
this.fileIngestStartTime = fileIngestStartTime;
this.jobCancelled = jobCancelled;
this.jobCancellationReason = cancellationReason;
this.cancelledDataSourceModules = new ArrayList<>(DataSourceIngestJob.this.cancelledDataSourceIngestModules);
this.cancelledDataSourceModules = cancelledModules;
if (getIngestTasksSnapshot) {
synchronized (DataSourceIngestJob.this.fileIngestProgressLock) {
this.processedFiles = DataSourceIngestJob.this.processedFiles;
this.estimatedFilesToProcess = DataSourceIngestJob.this.estimatedFilesToProcess;
this.snapShotTime = new Date().getTime();
}
this.tasksSnapshot = DataSourceIngestJob.taskScheduler.getTasksSnapshotForJob(this.jobId);
} else {
this.processedFiles = 0;
this.estimatedFilesToProcess = 0;
this.snapShotTime = new Date().getTime();
this.tasksSnapshot = null;
}
this.processedFiles = processedFiles;
this.estimatedFilesToProcess = estimatedFilesToProcess;
this.snapShotTime = snapshotTime;
this.tasksSnapshot = tasksSnapshot;
}
/**
@ -1190,11 +1213,11 @@ final class DataSourceIngestJob {
return this.dataSourceLevelIngestModule;
}
boolean fileIngestIsRunning() {
boolean getFileIngestIsRunning() {
return this.fileIngestRunning;
}
Date fileIngestStartTime() {
Date getFileIngestStartTime() {
return this.fileIngestStartTime;
}

View File

@ -355,10 +355,10 @@ public final class IngestJob {
dataSourceModule = new DataSourceIngestModuleHandle(dataSourceJobs.get(snapshot.getJobId()), module);
}
}
if (snapshot.fileIngestIsRunning()) {
if (snapshot.getFileIngestIsRunning()) {
fileIngestRunning = true;
}
Date childFileIngestStartTime = snapshot.fileIngestStartTime();
Date childFileIngestStartTime = snapshot.getFileIngestStartTime();
if (null != childFileIngestStartTime && (null == fileIngestStartTime || childFileIngestStartTime.before(fileIngestStartTime))) {
fileIngestStartTime = childFileIngestStartTime;
}

View File

@ -22,6 +22,7 @@ import com.google.common.util.concurrent.ThreadFactoryBuilder;
import java.awt.EventQueue;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -107,7 +108,7 @@ import org.sleuthkit.datamodel.Content;
* job progress, and ingest module run times.
*/
@ThreadSafe
public class IngestManager {
public class IngestManager implements IngestProgressSnapshotProvider {
private final static Logger logger = Logger.getLogger(IngestManager.class.getName());
private final static String INGEST_JOB_EVENT_CHANNEL_NAME = "%s-Ingest-Job-Events"; //NON-NLS
@ -756,7 +757,8 @@ public class IngestManager {
*
* @return Map of module name to run time (in milliseconds)
*/
Map<String, Long> getModuleRunTimes() {
@Override
public Map<String, Long> getModuleRunTimes() {
synchronized (ingestModuleRunTimes) {
Map<String, Long> times = new HashMap<>(ingestModuleRunTimes);
return times;
@ -769,7 +771,8 @@ public class IngestManager {
*
* @return A collection of ingest manager ingest task snapshots.
*/
List<IngestThreadActivitySnapshot> getIngestThreadActivitySnapshots() {
@Override
public List<IngestThreadActivitySnapshot> getIngestThreadActivitySnapshots() {
return new ArrayList<>(ingestThreadActivitySnapshots.values());
}
@ -778,7 +781,8 @@ public class IngestManager {
*
* @return A list of ingest job state snapshots.
*/
List<DataSourceIngestJob.Snapshot> getIngestJobSnapshots() {
@Override
public List<DataSourceIngestJob.Snapshot> getIngestJobSnapshots() {
List<DataSourceIngestJob.Snapshot> snapShots = new ArrayList<>();
synchronized (ingestJobsById) {
ingestJobsById.values().forEach((job) -> {
@ -916,7 +920,9 @@ public class IngestManager {
* running in an ingest thread.
*/
@Immutable
static final class IngestThreadActivitySnapshot {
public static final class IngestThreadActivitySnapshot implements Serializable {
private static final long serialVersionUID = 1L;
private final long threadId;
private final Date startTime;

View File

@ -50,12 +50,14 @@ public final class IngestProgressSnapshotDialog extends JDialog {
/**
* Constructs an instance of the dialog with its own frame. Could be modal.
* Uses the given provider as the source of data for the dialog.
*
* @param owner - the owner of this dialog. If this dialog should be
* modal, the owner gets set to non modal.
* @param shouldBeModal - true if this should be modal, false otherwise.
* @param provider - the provider to use as the source of data.
*/
public IngestProgressSnapshotDialog(Container owner, Boolean shouldBeModal) {
public IngestProgressSnapshotDialog(Container owner, Boolean shouldBeModal, IngestProgressSnapshotProvider provider) {
super((Window) owner, TITLE, ModalityType.MODELESS);
if (shouldBeModal && owner instanceof JDialog) { // if called from a modal dialog, manipulate the parent be just under this in z order, and not modal.
final JDialog pseudoOwner = (JDialog) owner;
@ -82,7 +84,7 @@ public final class IngestProgressSnapshotDialog extends JDialog {
this.getRootPane().registerKeyboardAction(e -> {
this.dispose();
}, KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_IN_FOCUSED_WINDOW);
add(new IngestProgressSnapshotPanel(this));
add(new IngestProgressSnapshotPanel(this, provider));
pack();
setResizable(false);
if (shouldBeModal) { // if called from a modal dialog, become modal, otherwise don't.
@ -90,4 +92,17 @@ public final class IngestProgressSnapshotDialog extends JDialog {
}
setVisible(true);
}
/**
* Constructs an instance of the dialog with its own frame. Could be modal.
* Uses the internal IngestManager instance as the source of data for the
* dialog
*
* @param owner - the owner of this dialog. If this dialog should be
* modal, the owner gets set to non modal.
* @param shouldBeModal - true if this should be modal, false otherwise.
*/
public IngestProgressSnapshotDialog(Container owner, Boolean shouldBeModal) {
this(owner, shouldBeModal, IngestManager.getInstance());
}
}

View File

@ -33,15 +33,17 @@ import org.openide.util.NbBundle;
/**
* A panel that displays ingest task progress snapshots.
*/
public class IngestProgressSnapshotPanel extends javax.swing.JPanel {
class IngestProgressSnapshotPanel extends javax.swing.JPanel {
private final JDialog parent;
private final IngestProgressSnapshotProvider snapshotProvider;
private final IngestThreadActivitySnapshotsTableModel threadActivityTableModel;
private final IngestJobTableModel jobTableModel;
private final ModuleTableModel moduleTableModel;
IngestProgressSnapshotPanel(JDialog parent) {
IngestProgressSnapshotPanel(JDialog parent, IngestProgressSnapshotProvider snapshotProvider) {
this.parent = parent;
this.snapshotProvider = snapshotProvider;
threadActivityTableModel = new IngestThreadActivitySnapshotsTableModel();
jobTableModel = new IngestJobTableModel();
moduleTableModel = new ModuleTableModel();
@ -105,7 +107,7 @@ public class IngestProgressSnapshotPanel extends javax.swing.JPanel {
}
private void refresh() {
snapshots = IngestManager.getInstance().getIngestThreadActivitySnapshots();
snapshots = snapshotProvider.getIngestThreadActivitySnapshots();
fireTableDataChanged();
}
@ -187,7 +189,7 @@ public class IngestProgressSnapshotPanel extends javax.swing.JPanel {
}
private void refresh() {
jobSnapshots = IngestManager.getInstance().getIngestJobSnapshots();
jobSnapshots = snapshotProvider.getIngestJobSnapshots();
fireTableDataChanged();
}
@ -299,7 +301,7 @@ public class IngestProgressSnapshotPanel extends javax.swing.JPanel {
}
private void refresh() {
Map<String, Long> moduleStatMap = IngestManager.getInstance().getModuleRunTimes();
Map<String, Long> moduleStatMap = snapshotProvider.getModuleRunTimes();
moduleStats.clear();
totalTime = 0;
for (String k : moduleStatMap.keySet()) {

View File

@ -0,0 +1,49 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* 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 org.sleuthkit.autopsy.ingest;
import java.util.List;
import java.util.Map;
/**
* Interface that provides a snapshot of ingest progress.
*/
public interface IngestProgressSnapshotProvider {
/**
* Get a snapshot of the state of ingest threads.
*
* @return A list of IngestThreadActivitySnapshot
*/
List<IngestManager.IngestThreadActivitySnapshot> getIngestThreadActivitySnapshots();
/**
* Get a snapshot of the state of ingest jobs.
*
* @return A list of ingest job snapshots.
*/
List<DataSourceIngestJob.Snapshot> getIngestJobSnapshots();
/**
* Gets the cumulative run times for the ingest module.
*
* @return Map of module name to run time (in milliseconds)
*/
Map<String, Long> getModuleRunTimes();
}

View File

@ -18,6 +18,7 @@
*/
package org.sleuthkit.autopsy.ingest;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
@ -555,7 +556,11 @@ final class IngestTasksScheduler {
* @return
*/
synchronized IngestJobTasksSnapshot getTasksSnapshotForJob(long jobId) {
return new IngestJobTasksSnapshot(jobId);
return new IngestJobTasksSnapshot(jobId, this.dataSourceIngestThreadQueue.countQueuedTasksForJob(jobId),
countTasksForJob(this.rootFileTaskQueue, jobId),
countTasksForJob(this.pendingFileTaskQueue, jobId),
this.fileIngestThreadsQueue.countQueuedTasksForJob(jobId),
this.dataSourceIngestThreadQueue.countRunningTasksForJob(jobId) + this.fileIngestThreadsQueue.countRunningTasksForJob(jobId));
}
/**
@ -825,8 +830,9 @@ final class IngestTasksScheduler {
/**
* A snapshot of ingest tasks data for an ingest job.
*/
class IngestJobTasksSnapshot {
public static final class IngestJobTasksSnapshot implements Serializable {
private static final long serialVersionUID = 1L;
private final long jobId;
private final long dsQueueSize;
private final long rootQueueSize;
@ -839,13 +845,13 @@ final class IngestTasksScheduler {
*
* @param jobId The identifier associated with the job.
*/
IngestJobTasksSnapshot(long jobId) {
IngestJobTasksSnapshot(long jobId, long dsQueueSize, long rootQueueSize, long dirQueueSize, long fileQueueSize, long runningListSize) {
this.jobId = jobId;
this.dsQueueSize = IngestTasksScheduler.this.dataSourceIngestThreadQueue.countQueuedTasksForJob(jobId);
this.rootQueueSize = countTasksForJob(IngestTasksScheduler.this.rootFileTaskQueue, jobId);
this.dirQueueSize = countTasksForJob(IngestTasksScheduler.this.pendingFileTaskQueue, jobId);
this.fileQueueSize = IngestTasksScheduler.this.fileIngestThreadsQueue.countQueuedTasksForJob(jobId);;
this.runningListSize = IngestTasksScheduler.this.dataSourceIngestThreadQueue.countRunningTasksForJob(jobId) + IngestTasksScheduler.this.fileIngestThreadsQueue.countRunningTasksForJob(jobId);
this.dsQueueSize = dsQueueSize;
this.rootQueueSize = rootQueueSize;
this.dirQueueSize = dirQueueSize;
this.fileQueueSize = fileQueueSize;
this.runningListSize = runningListSize;
}
/**

View File

@ -143,19 +143,20 @@ final class AutoIngestAdminActions {
static final class ProgressDialogAction extends AbstractAction {
private static final long serialVersionUID = 1L;
private final AutoIngestJob job;
ProgressDialogAction() {
ProgressDialogAction(AutoIngestJob job) {
super(Bundle.AutoIngestAdminActions_progressDialogAction_title());
this.job = job;
}
@Override
public void actionPerformed(ActionEvent e) {
//TODO JIRA-3734
final AutoIngestDashboardTopComponent tc = (AutoIngestDashboardTopComponent) WindowManager.getDefault().findTopComponent(AutoIngestDashboardTopComponent.PREFERRED_ID);
if (tc != null) {
AutoIngestDashboard dashboard = tc.getAutoIngestDashboard();
if (dashboard != null) {
new IngestProgressSnapshotDialog(dashboard.getTopLevelAncestor(), true);
new IngestProgressSnapshotDialog(dashboard.getTopLevelAncestor(), true, job);
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2017 Basis Technology Corp.
* Copyright 2011-2018 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -25,23 +25,28 @@ import java.time.Instant;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import javax.annotation.concurrent.GuardedBy;
import javax.annotation.concurrent.Immutable;
import javax.annotation.concurrent.ThreadSafe;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.coreutils.NetworkUtils;
import org.sleuthkit.autopsy.ingest.DataSourceIngestJob.Snapshot;
import org.sleuthkit.autopsy.ingest.IngestJob;
import org.sleuthkit.autopsy.ingest.IngestManager.IngestThreadActivitySnapshot;
import org.sleuthkit.autopsy.ingest.IngestProgressSnapshotProvider;
/**
* An automated ingest job, which is an ingest job performed by the automated
* ingest service.
*/
@ThreadSafe
final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializable {
final class AutoIngestJob implements Comparable<AutoIngestJob>, IngestProgressSnapshotProvider, Serializable {
private static final long serialVersionUID = 1L;
private static final int CURRENT_VERSION = 2;
private static final int CURRENT_VERSION = 3;
private static final int DEFAULT_PRIORITY = 0;
private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName();
@ -89,6 +94,13 @@ final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializable {
@GuardedBy("this")
private long dataSourceSize;
/*
* Version 3 fields.
*/
private List<IngestThreadActivitySnapshot> ingestThreadsSnapshot;
private List<Snapshot> ingestJobsSnapshot;
private Map<String, Long> moduleRunTimesSnapshot;
/**
* Constructs a new automated ingest job. All job state not specified in the
* job manifest is set to the default state for a new job.
@ -125,6 +137,13 @@ final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializable {
* Version 2 fields.
*/
this.dataSourceSize = 0;
/*
* Version 3 fields.
*/
this.ingestThreadsSnapshot = Collections.emptyList();
this.ingestJobsSnapshot = Collections.emptyList();
this.moduleRunTimesSnapshot = Collections.emptyMap();
} catch (Exception ex) {
throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex);
}
@ -167,6 +186,13 @@ final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializable {
* Version 2 fields.
*/
this.dataSourceSize = nodeData.getDataSourceSize();
/*
* Version 3 fields
*/
this.ingestThreadsSnapshot = Collections.emptyList();
this.ingestJobsSnapshot = Collections.emptyList();
this.moduleRunTimesSnapshot = Collections.emptyMap();
} catch (Exception ex) {
throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex);
}
@ -340,6 +366,31 @@ final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializable {
return this.ingestJob;
}
/**
* Sets the ingest thread snapshot for the auto ingest job.
*
* @param snapshot
*/
synchronized void setIngestThreadSnapshot(List<IngestThreadActivitySnapshot> snapshot) {
this.ingestThreadsSnapshot = snapshot;
}
/**
* Sets the ingest job snapshot for the auto ingest job.
* @param snapshot
*/
synchronized void setIngestJobsSnapshot(List<Snapshot> snapshot) {
this.ingestJobsSnapshot = snapshot;
}
/**
* Sets the module run times snapshot for the auto ingest job.
* @param snapshot
*/
synchronized void setModuleRuntimesSnapshot(Map<String, Long> snapshot) {
this.moduleRunTimesSnapshot = snapshot;
}
/**
* Cancels the job.
*/
@ -541,6 +592,21 @@ final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializable {
return -this.getManifest().getDateFileCreated().compareTo(otherJob.getManifest().getDateFileCreated());
}
@Override
public List<IngestThreadActivitySnapshot> getIngestThreadActivitySnapshots() {
return this.ingestThreadsSnapshot;
}
@Override
public List<Snapshot> getIngestJobSnapshots() {
return this.ingestJobsSnapshot;
}
@Override
public Map<String, Long> getModuleRunTimes() {
return this.moduleRunTimesSnapshot;
}
/**
* Comparator that supports doing a descending sort of jobs based on job
* completion date.

View File

@ -260,9 +260,9 @@ final class AutoIngestJobsNode extends AbstractNode {
actions.add(deprioritizeCaseAction);
break;
case RUNNING_JOB:
actions.add(new AutoIngestAdminActions.ProgressDialogAction());
actions.add(new AutoIngestAdminActions.ProgressDialogAction(autoIngestJob));
actions.add(new AutoIngestAdminActions.CancelJobAction(autoIngestJob));
actions.add(new AutoIngestAdminActions.CancelModuleAction());
// actions.add(new AutoIngestAdminActions.CancelModuleAction());
break;
case COMPLETED_JOB:
actions.add(new AutoIngestAdminActions.ReprocessJobAction(autoIngestJob));

View File

@ -3052,6 +3052,9 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
synchronized (jobsLock) {
if (currentJob != null) {
currentJob.getProcessingStageDetails();
currentJob.setIngestThreadSnapshot(IngestManager.getInstance().getIngestThreadActivitySnapshots());
currentJob.setIngestJobsSnapshot(IngestManager.getInstance().getIngestJobSnapshots());
currentJob.setModuleRuntimesSnapshot(IngestManager.getInstance().getModuleRunTimes());
setChanged();
notifyObservers(Event.JOB_STATUS_UPDATED);
updateCoordinationServiceManifestNode(currentJob);

View File

@ -188,7 +188,17 @@ final class AutoIngestMonitor extends Observable implements PropertyChangeListen
*/
AutoIngestJob job = event.getJob();
jobsSnapshot.removePendingJob(job);
jobsSnapshot.addOrReplaceRunningJob(job);
// Update the state of the existing job in the running jobs table
for (AutoIngestJob runningJob : jobsSnapshot.getRunningJobs()) {
if (runningJob.equals(job)) {
runningJob.setIngestJobsSnapshot(job.getIngestJobSnapshots());
runningJob.setIngestThreadSnapshot(job.getIngestThreadActivitySnapshots());
runningJob.setModuleRuntimesSnapshot(job.getModuleRunTimes());
runningJob.setProcessingStage(job.getProcessingStage(), job.getProcessingStageStartDate());
runningJob.setProcessingStatus(job.getProcessingStatus());
}
}
setChanged();
notifyObservers(jobsSnapshot);
}