in x-pack/platform/plugins/shared/ml/server/models/job_service/jobs.ts [386:545]
async function createFullJobsList(jobIds: string[] = []) {
const jobs: CombinedJobWithStats[] = [];
const groups: { [jobId: string]: string[] } = Object.create(null);
const datafeeds: { [id: string]: DatafeedWithStats } = Object.create(null);
const calendarsByJobId: { [jobId: string]: string[] } = Object.create(null);
const globalCalendars: string[] = [];
const jobIdsString = jobIds.join();
const [
jobResults,
jobStatsResults,
datafeedResults,
datafeedStatsResults,
calendarResults,
latestBucketTimestampByJob,
] = await Promise.all([
mlClient.getJobs(jobIds.length > 0 ? { job_id: jobIdsString } : undefined),
mlClient.getJobStats(jobIds.length > 0 ? { job_id: jobIdsString } : undefined),
mlClient.getDatafeeds(),
mlClient.getDatafeedStats(),
calMngr.getAllCalendars(),
getLatestBucketTimestampByJob(),
]);
if (datafeedResults && datafeedResults.datafeeds) {
datafeedResults.datafeeds.forEach((datafeed) => {
if (datafeedStatsResults && datafeedStatsResults.datafeeds) {
const datafeedStats = datafeedStatsResults.datafeeds.find(
(ds) => ds.datafeed_id === datafeed.datafeed_id
);
if (datafeedStats) {
datafeeds[datafeed.job_id] = { ...datafeed, ...datafeedStats };
}
}
});
}
// create list of jobs per group.
// used for assigning calendars to jobs when a calendar has
// only been attached to a group
if (jobResults && jobResults.jobs) {
jobResults.jobs.forEach((job) => {
calendarsByJobId[job.job_id] = [];
if (job.groups !== undefined) {
job.groups.forEach((gId) => {
if (groups[gId] === undefined) {
groups[gId] = [];
}
groups[gId].push(job.job_id);
});
}
});
}
// assign calendars to jobs
if (calendarResults) {
calendarResults.forEach((cal) => {
cal.job_ids.forEach((id) => {
if (id === GLOBAL_CALENDAR) {
globalCalendars.push(cal.calendar_id);
} else if (groups[id]) {
groups[id].forEach((jId) => {
if (calendarsByJobId[jId] !== undefined) {
calendarsByJobId[jId].push(cal.calendar_id);
}
});
} else {
if (calendarsByJobId[id] !== undefined) {
calendarsByJobId[id].push(cal.calendar_id);
}
}
});
});
// de-duplicate calendars
for (const cal in calendarsByJobId) {
if (Object.hasOwn(calendarsByJobId, cal)) {
calendarsByJobId[cal] = uniq(calendarsByJobId[cal]);
}
}
}
// create jobs objects containing job stats, datafeeds, datafeed stats and calendars
if (jobResults && jobResults.jobs) {
jobResults.jobs.forEach((job) => {
let tempJob = job as CombinedJobWithStats;
const calendars: string[] = [
...(calendarsByJobId[tempJob.job_id] || []),
...(globalCalendars || []),
];
if (calendars.length) {
tempJob.calendars = calendars;
}
if (jobStatsResults && jobStatsResults.jobs) {
const jobStats = jobStatsResults.jobs.find((js) => js.job_id === tempJob.job_id);
if (jobStats !== undefined) {
tempJob = { ...tempJob, ...jobStats };
if (jobStats.node) {
tempJob.node = jobStats.node;
}
if (jobStats.open_time) {
tempJob.open_time = jobStats.open_time;
}
// Add in the timestamp of the last bucket processed for each job if available.
const latestBucketTimestamp =
latestBucketTimestampByJob && latestBucketTimestampByJob[tempJob.job_id];
if (latestBucketTimestamp) {
tempJob.data_counts.latest_bucket_timestamp = latestBucketTimestamp;
}
}
}
const datafeed = datafeeds[tempJob.job_id];
if (datafeed !== undefined) {
tempJob.datafeed_config = datafeed;
}
jobs.push(tempJob);
});
if (rulesClient) {
const mlAlertingRules = await rulesClient.find<MlAnomalyDetectionAlertParams>({
options: {
filter: `alert.attributes.alertTypeId:${ML_ALERT_TYPES.ANOMALY_DETECTION}`,
perPage: 1000,
},
});
mlAlertingRules.data.forEach((curr) => {
const {
params: {
jobSelection: { jobIds: ruleJobIds, groupIds: ruleGroupIds },
},
} = curr;
jobs.forEach((j) => {
const isIncluded =
(Array.isArray(ruleJobIds) && ruleJobIds.includes(j.job_id)) ||
(Array.isArray(ruleGroupIds) &&
Array.isArray(j.groups) &&
j.groups.some((g) => ruleGroupIds.includes(g)));
if (isIncluded) {
if (Array.isArray(j.alerting_rules)) {
j.alerting_rules.push(curr);
} else {
j.alerting_rules = [curr];
}
}
});
});
}
}
return jobs;
}