Agent Improvements/Fixes (#1284)

* fixed UI bugs and increased jobs history page perf

* cached full error message

* load histories for jobs with errors first

* cr comments
This commit is contained in:
Aditya Bist
2018-05-01 17:42:11 -07:00
committed by GitHub
parent 46fb68214f
commit 6f10f7a21a
4 changed files with 66 additions and 40 deletions

View File

@@ -111,7 +111,7 @@ export class JobHistoryComponent extends Disposable implements OnInit {
} else { } else {
tree.setFocus(element, payload); tree.setFocus(element, payload);
tree.setSelection([element], payload); tree.setSelection([element], payload);
self.setStepsTree(element); self.setStepsTree(element);
} }
return true; return true;
}; };
@@ -192,7 +192,8 @@ export class JobHistoryComponent extends Disposable implements OnInit {
private setStepsTree(element: any) { private setStepsTree(element: any) {
const self = this; const self = this;
self.agentJobHistoryInfo = self._treeController.jobHistories.filter(history => history.instanceId === element.instanceID)[0]; self.agentJobHistoryInfo = self._treeController.jobHistories.find(
history => self.formatTime(history.runDate) === self.formatTime(element.runDate));
if (self.agentJobHistoryInfo) { if (self.agentJobHistoryInfo) {
self.agentJobHistoryInfo.runDate = self.formatTime(self.agentJobHistoryInfo.runDate); self.agentJobHistoryInfo.runDate = self.formatTime(self.agentJobHistoryInfo.runDate);
if (self.agentJobHistoryInfo.steps) { if (self.agentJobHistoryInfo.steps) {
@@ -242,7 +243,7 @@ export class JobHistoryComponent extends Disposable implements OnInit {
private convertToJobHistoryRow(historyInfo: AgentJobHistoryInfo): JobHistoryRow { private convertToJobHistoryRow(historyInfo: AgentJobHistoryInfo): JobHistoryRow {
let jobHistoryRow = new JobHistoryRow(); let jobHistoryRow = new JobHistoryRow();
jobHistoryRow.runDate = historyInfo.runDate; jobHistoryRow.runDate = this.formatTime(historyInfo.runDate);
jobHistoryRow.runStatus = AgentJobUtilities.convertToStatusString(historyInfo.runStatus); jobHistoryRow.runStatus = AgentJobUtilities.convertToStatusString(historyInfo.runStatus);
jobHistoryRow.instanceID = historyInfo.instanceId; jobHistoryRow.instanceID = historyInfo.instanceId;
return jobHistoryRow; return jobHistoryRow;

View File

@@ -60,9 +60,11 @@ export class JobHistoryController extends TreeDefaults.DefaultController {
public onKeyDownWrapper(tree: tree.ITree, event: IKeyboardEvent): boolean { public onKeyDownWrapper(tree: tree.ITree, event: IKeyboardEvent): boolean {
if (event.code === 'ArrowDown' || event.keyCode === 40) { if (event.code === 'ArrowDown' || event.keyCode === 40) {
return super.onDown(tree, event); super.onDown(tree, event);
return super.onEnter(tree, event);
} else if (event.code === 'ArrowUp' || event.keyCode === 38) { } else if (event.code === 'ArrowUp' || event.keyCode === 38) {
return super.onUp(tree, event); super.onUp(tree, event);
return super.onEnter(tree, event);
} else { } else {
event.preventDefault(); event.preventDefault();
event.stopPropagation(); event.stopPropagation();

View File

@@ -157,9 +157,7 @@ export class JobsViewComponent implements AfterContentChecked {
let job = self.getJob(args); let job = self.getJob(args);
self._agentViewComponent.jobId = job.jobId; self._agentViewComponent.jobId = job.jobId;
self._agentViewComponent.agentJobInfo = job; self._agentViewComponent.agentJobInfo = job;
setTimeout(() => { self._agentViewComponent.showHistory = true;
self._agentViewComponent.showHistory = true;
}, 500);
}); });
if (cached && this._agentViewComponent.refresh !== true) { if (cached && this._agentViewComponent.refresh !== true) {
this.onJobsAvailable(this._jobCacheObject.jobs); this.onJobsAvailable(this._jobCacheObject.jobs);
@@ -290,44 +288,69 @@ export class JobsViewComponent implements AfterContentChecked {
this.rowDetail.applyTemplateNewLineHeight(item, true); this.rowDetail.applyTemplateNewLineHeight(item, true);
} }
private loadJobHistories() { private loadJobHistories(): void {
const self = this;
if (this.jobs) { if (this.jobs) {
let erroredJobs = 0; let erroredJobs = 0;
for (let i = 0; i < this.jobs.length; i++) { let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri;
let job = this.jobs[i]; let separatedJobs = this.separateFailingJobs();
let ownerUri: string = this._dashboardService.connectionManagementService.connectionInfo.ownerUri; // grab histories of the failing jobs first
this._jobManagementService.getJobHistory(ownerUri, job.jobId).then((result) => { // so they can be expanded quicker
if (result.jobs) { let failing = separatedJobs[0];
self.jobHistories[job.jobId] = result.jobs; this.curateJobHistory(failing, ownerUri);
self._jobCacheObject.setJobHistory(job.jobId, result.jobs); let passing = separatedJobs[1];
if (self._agentViewComponent.expanded.has(job.jobId)) { this.curateJobHistory(passing, ownerUri);
let jobHistory = self._jobCacheObject.getJobHistory(job.jobId)[0];
let item = self.dataView.getItemById(job.jobId + '.error');
let noStepsMessage = nls.localize('jobsView.noSteps', 'No Steps available for this job.');
let errorMessage = jobHistory ? jobHistory.message: noStepsMessage;
item['name'] = nls.localize('jobsView.error', 'Error: ') + errorMessage;
self._agentViewComponent.setExpanded(job.jobId, errorMessage);
self.dataView.updateItem(job.jobId + '.error', item);
}
}
});
}
} }
} }
private isErrorRow(jobName: string) { private separateFailingJobs(): sqlops.AgentJobInfo[][] {
return jobName.includes('Error'); let failing = [];
let nonFailing = [];
for (let i = 0; i < this.jobs.length; i++) {
if (this.jobs[i].lastRunOutcome === 0) {
failing.push(this.jobs[i]);
} else {
nonFailing.push(this.jobs[i]);
}
}
return [failing, nonFailing];
}
private isErrorRow(cell: HTMLElement) {
return cell.classList.contains('error-row');
} }
private getJob(args: Slick.OnClickEventArgs<any>): sqlops.AgentJobInfo { private getJob(args: Slick.OnClickEventArgs<any>): sqlops.AgentJobInfo {
let row = args.row; let row = args.row;
let jobName = args.grid.getCellNode(row, 1).innerText.trim(); let jobName: string;
if (this.isErrorRow(jobName)) { let cell = args.grid.getCellNode(row, 1);
if (this.isErrorRow(cell)) {
jobName = args.grid.getCellNode(row-1, 1).innerText.trim(); jobName = args.grid.getCellNode(row-1, 1).innerText.trim();
} else {
jobName = cell.innerText.trim();
} }
let job = this.jobs.filter(job => job.name === jobName)[0]; let job = this.jobs.filter(job => job.name === jobName)[0];
return job; return job;
} }
private curateJobHistory(jobs: sqlops.AgentJobInfo[], ownerUri: string) {
const self = this;
for (let i = 0; i < jobs.length; i++) {
let job = jobs[i];
this._jobManagementService.getJobHistory(ownerUri, job.jobId).then((result) => {
if (result && result.jobs) {
self.jobHistories[job.jobId] = result.jobs;
self._jobCacheObject.setJobHistory(job.jobId, result.jobs);
if (self._agentViewComponent.expanded.has(job.jobId)) {
let jobHistory = self._jobCacheObject.getJobHistory(job.jobId)[result.jobs.length-1];
let item = self.dataView.getItemById(job.jobId + '.error');
let noStepsMessage = nls.localize('jobsView.noSteps', 'No Steps available for this job.');
let errorMessage = jobHistory ? jobHistory.message: noStepsMessage;
item['name'] = nls.localize('jobsView.error', 'Error: ') + errorMessage;
self._agentViewComponent.setExpanded(job.jobId, item['name']);
self.dataView.updateItem(job.jobId + '.error', item);
}
}
});
}
}
} }

12
src/sql/sqlops.d.ts vendored
View File

@@ -1061,7 +1061,7 @@ declare module 'sqlops' {
} }
export interface AgentJobStep { export interface AgentJobStep {
stepId: number; stepId: string;
stepName: string; stepName: string;
message: string; message: string;
runDate: string; runDate: string;
@@ -1070,20 +1070,20 @@ declare module 'sqlops' {
export interface AgentJobHistoryInfo { export interface AgentJobHistoryInfo {
instanceId: number; instanceId: number;
sqlMessageId: number; sqlMessageId: string;
message: string; message: string;
stepId: number; stepId: string;
stepName: string; stepName: string;
sqlSeverity: number; sqlSeverity: string;
jobId: string; jobId: string;
jobName: string; jobName: string;
runStatus: number; runStatus: number;
runDate: string; runDate: string;
runDuration: number; runDuration: string;
operatorEmailed: string; operatorEmailed: string;
operatorNetsent: string; operatorNetsent: string;
operatorPaged: string; operatorPaged: string;
retriesAttempted: number; retriesAttempted: string;
server: string; server: string;
steps: AgentJobStep[]; steps: AgentJobStep[];
} }