updates to job results performance

This commit is contained in:
John Mitchell
2017-01-20 17:41:09 -05:00
parent 037d8a1ee4
commit 55034f1a78
7 changed files with 125 additions and 53 deletions

View File

@@ -2234,3 +2234,8 @@ a:hover {
padding-left: 2px; padding-left: 2px;
width: 14px; width: 14px;
} }
button[disabled],
html input[disabled] {
cursor: not-allowed;
}

View File

@@ -35,11 +35,14 @@
<div class="JobResultsStdOut-numberColumnPreload"></div> <div class="JobResultsStdOut-numberColumnPreload"></div>
<div id='lineAnchor' class="JobResultsStdOut-lineAnchor"></div> <div id='lineAnchor' class="JobResultsStdOut-lineAnchor"></div>
<div class="JobResultsStdOut-aLineOfStdOut" <div class="JobResultsStdOut-aLineOfStdOut"
ng-show="tooManyEvents"> ng-show="tooManyEvents || tooManyPastEvents">
<div class="JobResultsStdOut-lineNumberColumn"> <div class="JobResultsStdOut-lineNumberColumn">
<span class="JobResultsStdOut-lineExpander"> </span> <span class="JobResultsStdOut-lineExpander"> </span>
</div> </div>
<div class="JobResultsStdOut-stdoutColumn JobResultsStdOut-stdoutColumn--tooMany">The standard output is too large to display. Please specify additional filters to narrow the standard out.</div> <div class="JobResultsStdOut-stdoutColumn JobResultsStdOut-stdoutColumn--tooMany"
ng-show="tooManyEvents">The standard output is too large to display. Please specify additional filters to narrow the standard out.</div>
<div class="JobResultsStdOut-stdoutColumn JobResultsStdOut-stdoutColumn--tooMany"
ng-show="tooManyPastEvents">Too much previous output to display. Showing running standard output.</div>
</div> </div>
<div id="followAnchor" <div id="followAnchor"
class="JobResultsStdOut-followAnchor"> class="JobResultsStdOut-followAnchor">

View File

@@ -1,5 +1,5 @@
export default ['jobData', 'jobDataOptions', 'jobLabels', 'jobFinished', 'count', '$scope', 'ParseTypeChange', 'ParseVariableString', 'jobResultsService', 'eventQueue', '$compile', '$log', 'Dataset', '$q', 'Rest', '$state', 'QuerySet', '$rootScope', 'moment', 'i18n', export default ['jobData', 'jobDataOptions', 'jobLabels', 'jobFinished', 'count', '$scope', 'ParseTypeChange', 'ParseVariableString', 'jobResultsService', 'eventQueue', '$compile', '$log', 'Dataset', '$q', 'Rest', '$state', 'QuerySet', '$rootScope', 'moment', '$stateParams', 'i18n',
function(jobData, jobDataOptions, jobLabels, jobFinished, count, $scope, ParseTypeChange, ParseVariableString, jobResultsService, eventQueue, $compile, $log, Dataset, $q, Rest, $state, QuerySet, $rootScope, moment, i18n) { function(jobData, jobDataOptions, jobLabels, jobFinished, count, $scope, ParseTypeChange, ParseVariableString, jobResultsService, eventQueue, $compile, $log, Dataset, $q, Rest, $state, QuerySet, $rootScope, moment, $stateParams, i18n) {
var toDestroy = []; var toDestroy = [];
var cancelRequests = false; var cancelRequests = false;
@@ -9,6 +9,25 @@ function(jobData, jobDataOptions, jobLabels, jobFinished, count, $scope, ParseTy
// this allows you to manage the timing of rest-call based events as // this allows you to manage the timing of rest-call based events as
// filters are updated. see processPage for more info // filters are updated. see processPage for more info
var currentContext = 1; var currentContext = 1;
$scope.firstCounterFromSocket = -1;
// if the user enters the page mid-run, reset the search to include a param
// to only grab events less than the first counter from the websocket events
toDestroy.push($scope.$watch('firstCounterFromSocket', function(counter) {
if (counter > -1) {
// make it so that the search include a counter less than the
// first counter from the socket
let params = _.cloneDeep($stateParams.job_event_search);
params.counter__lte = "" + counter;
Dataset = QuerySet.search(jobData.related.job_events,
params);
Dataset.then(function(actualDataset) {
$scope.job_event_dataset = actualDataset.data;
});
}
}));
// used for tag search // used for tag search
$scope.job_event_dataset = Dataset.data; $scope.job_event_dataset = Dataset.data;
@@ -424,57 +443,87 @@ function(jobData, jobDataOptions, jobLabels, jobFinished, count, $scope, ParseTy
// grab non-header recap lines // grab non-header recap lines
toDestroy.push($scope.$watch('job_event_dataset', function(val) { toDestroy.push($scope.$watch('job_event_dataset', function(val) {
eventQueue.initialize(); if (val) {
eventQueue.initialize();
Object.keys($scope.events) Object.keys($scope.events)
.forEach(v => { .forEach(v => {
// dont destroy scope events for skeleton lines // dont destroy scope events for skeleton lines
let name = $scope.events[v].event.name; let name = $scope.events[v].event.name;
if (!(name === "playbook_on_play_start" || if (!(name === "playbook_on_play_start" ||
name === "playbook_on_task_start" || name === "playbook_on_task_start" ||
name === "playbook_on_stats")) { name === "playbook_on_stats")) {
$scope.events[v].$destroy(); $scope.events[v].$destroy();
$scope.events[v] = null; $scope.events[v] = null;
delete $scope.events[v]; delete $scope.events[v];
}
});
// pause websocket events from coming in to the pane
$scope.gotPreviouslyRanEvents = $q.defer();
currentContext += 1;
let context = currentContext;
$( ".JobResultsStdOut-aLineOfStdOut.not_skeleton" ).remove();
$scope.hasSkeleton.promise.then(() => {
if (val.count > parseInt(val.maxEvents)) {
$(".header_task").hide();
$(".header_play").hide();
$scope.standardOutTooltip = '<div class="JobResults-downloadTooLarge"><div>' +
i18n._('The output is too large to display. Please download.') +
'</div>' +
'<div class="JobResults-downloadTooLarge--icon">' +
'<span class="fa-stack fa-lg">' +
'<i class="fa fa-circle fa-stack-1x"></i>' +
'<i class="fa fa-stack-1x icon-job-stdout-download-tooltip"></i>' +
'</span>' +
'</div>' +
'</div>';
if ($scope.job_status === "successful" ||
$scope.job_status === "failed" ||
$scope.job_status === "error" ||
$scope.job_status === "canceled") {
$scope.tooManyEvents = true;
$scope.tooManyPastEvents = false;
} else {
$scope.tooManyPastEvents = true;
$scope.tooManyEvents = false;
$scope.gotPreviouslyRanEvents.resolve("");
}
} else {
$(".header_task").show();
$(".header_play").show();
$scope.tooManyEvents = false;
$scope.tooManyPastEvents = false;
processPage(val, context);
} }
}); });
}
// pause websocket events from coming in to the pane
$scope.gotPreviouslyRanEvents = $q.defer();
currentContext += 1;
let context = currentContext;
$( ".JobResultsStdOut-aLineOfStdOut.not_skeleton" ).remove();
$scope.hasSkeleton.promise.then(() => {
if (val.count > parseInt(val.maxEvents)) {
$(".header_task").hide();
$(".header_play").hide();
$scope.tooManyEvents = true;
$scope.standardOutTooltip = '<div class="JobResults-downloadTooLarge"><div>' +
i18n._('The output is too large to display. Please download.') +
'</div>' +
'<div class="JobResults-downloadTooLarge--icon">' +
'<span class="fa-stack fa-lg">' +
'<i class="fa fa-circle fa-stack-1x"></i>' +
'<i class="fa fa-stack-1x icon-job-stdout-download-tooltip"></i>' +
'</span>' +
'</div>' +
'</div>';
} else {
$(".header_task").show();
$(".header_play").show();
$scope.tooManyEvents = false;
processPage(val, context);
}
});
})); }));
// Processing of job_events messages from the websocket // Processing of job_events messages from the websocket
toDestroy.push($scope.$on(`ws-job_events-${$scope.job.id}`, function(e, data) { toDestroy.push($scope.$on(`ws-job_events-${$scope.job.id}`, function(e, data) {
// use the lowest counter coming over the socket to retrigger pull data
// to only be for stuff lower than that id
//
// only do this for entering the jobs page mid-run (thus the
// data.counter is 1 conditional
if (data.counter === 1) {
$scope.firstCounterFromSocket = -2;
}
if ($scope.firstCounterFromSocket !== -2 &&
$scope.firstCounterFromSocket === -1 ||
data.counter < $scope.firstCounterFromSocket) {
$scope.firstCounterFromSocket = data.counter;
}
$q.all([$scope.gotPreviouslyRanEvents.promise, $q.all([$scope.gotPreviouslyRanEvents.promise,
$scope.hasSkeleton.promise]).then(() => { $scope.hasSkeleton.promise]).then(() => {
// put the line in the // put the line in the

View File

@@ -506,7 +506,9 @@
list="list" list="list"
collection="job_events" collection="job_events"
dataset="job_event_dataset" dataset="job_event_dataset"
search-tags="searchTags"> search-tags="searchTags"
disable-search="job_status == 'running' ||
job_status=='pending'">
</smart-search> </smart-search>
<job-results-standard-out></job-results-standard-out> <job-results-standard-out></job-results-standard-out>
</div> </div>

View File

@@ -6,6 +6,12 @@
import {templateUrl} from '../shared/template-url/template-url.factory'; import {templateUrl} from '../shared/template-url/template-url.factory';
const defaultParams = {
page_size: "200",
order_by: 'start_line',
not__event__in: 'playbook_on_start,playbook_on_play_start,playbook_on_task_start,playbook_on_stats'
}
export default { export default {
name: 'jobDetail', name: 'jobDetail',
url: '/jobs/{id: int}', url: '/jobs/{id: int}',
@@ -24,11 +30,7 @@ export default {
}, },
params: { params: {
job_event_search: { job_event_search: {
value: { value: defaultParams,
page_size: 100,
order_by: 'id',
not__event__in: 'playbook_on_start,playbook_on_play_start,playbook_on_task_start,playbook_on_stats'
},
dynamic: true, dynamic: true,
squash: '' squash: ''
} }
@@ -56,7 +58,7 @@ export default {
// flashing as rest data comes in. If the job is finished and // flashing as rest data comes in. If the job is finished and
// there's a playbook_on_stats event, go ahead and resolve the count // there's a playbook_on_stats event, go ahead and resolve the count
// so you don't get that flashing! // so you don't get that flashing!
count: ['jobData', 'jobResultsService', 'Rest', '$q', function(jobData, jobResultsService, Rest, $q) { count: ['jobData', 'jobResultsService', 'Rest', '$q', '$stateParams', '$state', function(jobData, jobResultsService, Rest, $q, $stateParams, $state) {
var defer = $q.defer(); var defer = $q.defer();
if (jobData.finished) { if (jobData.finished) {
// if the job is finished, grab the playbook_on_stats // if the job is finished, grab the playbook_on_stats
@@ -92,6 +94,15 @@ export default {
}, countFinished: false}); }, countFinished: false});
}); });
} else { } else {
// make sure to not include any extra
// search params for a running job (because we can't filter
// incoming job events)
if (!_.isEqual($stateParams.job_event_search, defaultParams)) {
let params = _.cloneDeep($stateParams);
params.job_event_search = defaultParams;
$state.go('.', params, { reload: true });
}
// job isn't finished so just send an empty count and read // job isn't finished so just send an empty count and read
// from events // from events
defer.resolve({val: { defer.resolve({val: {

View File

@@ -15,6 +15,7 @@ export default ['templateUrl',
dataset: '=', dataset: '=',
collection: '=', collection: '=',
searchTags: '=', searchTags: '=',
disableSearch: '='
}, },
controller: 'SmartSearchController', controller: 'SmartSearchController',
templateUrl: templateUrl('shared/smart-search/smart-search') templateUrl: templateUrl('shared/smart-search/smart-search')

View File

@@ -4,7 +4,8 @@
<div class="SmartSearch-searchTermContainer"> <div class="SmartSearch-searchTermContainer">
<!-- string search input --> <!-- string search input -->
<form name="smartSearch" class="SmartSearch-form" aw-enter-key="add(searchTerm)" novalidate> <form name="smartSearch" class="SmartSearch-form" aw-enter-key="add(searchTerm)" novalidate>
<input class="SmartSearch-input" ng-model="searchTerm" placeholder="Search"> <input class="SmartSearch-input" ng-model="searchTerm" placeholder="{{disableSearch ? 'Cannot search running job' : 'Search'}}"
ng-disabled="disableSearch">
</form> </form>
<div type="submit" class="SmartSearch-searchButton" ng-disabled="!searchTerm" ng-click="add(searchTerm)"> <div type="submit" class="SmartSearch-searchButton" ng-disabled="!searchTerm" ng-click="add(searchTerm)">
<i class="fa fa-search"></i> <i class="fa fa-search"></i>