in jobs/managers/task.ts [17:210]
export default async function refresh({ providers }: IReposJob): Promise<IReposJobResult> {
const graphProvider = providers.graphProvider;
const cacheHelper = providers.cacheProvider;
const insights = providers.insights;
const config = providers.config;
const linkProvider = await createAndInitializeLinkProviderInstance(providers, config);
console.log('reading all links to gather manager info ahead of any terminations');
const allLinks = await linkProvider.getAll();
console.log(`READ: ${allLinks.length} links`);
insights.trackEvent({ name: 'JobRefreshManagersReadLinks', properties: { links: String(allLinks.length) } });
let errors = 0;
let notFoundErrors = 0;
let errorList = [];
let managerUpdates = 0;
let managerSets = 0;
let managerMetadataUpdates = 0;
const userDetailsThroatCount = 1;
const secondsDelayAfterError = 1;
const secondsDelayAfterSuccess = 0.09; //0.1;
const managerInfoCachePeriodMinutes = 60 * 24 * 7 * 12; // 12 weeks
let processed = 0;
const bulkContacts = new Map<string, IMicrosoftIdentityServiceBasics | boolean>();
const throttle = throat(userDetailsThroatCount);
let unknownServiceAccounts: ICorporateLink[] = [];
const formerAccounts: ICorporateLink[] = [];
await Promise.all(allLinks.map((link: ICorporateLink) => throttle(async () => {
const employeeDirectoryId = link.corporateId;
++processed;
bulkContacts.set(link.corporateUsername, false);
if (processed % 25 === 0) {
console.log(`${processed}/${allLinks.length}.`);
}
if (link.isServiceAccount) {
console.log(`Service account: ${link.corporateUsername}`);
}
let info = null, infoError = null;
try {
info = await graphProvider.getUserAndManagerById(employeeDirectoryId);
if (link.isServiceAccount) {
console.log();
// console.dir(info);
console.log(`info OK for SA ${link.corporateUsername}`);
}
} catch (retrievalError) {
if (link.isServiceAccount) {
// console.dir(retrievalError);
console.log(`no info for SA: ${link.corporateUsername}`);
unknownServiceAccounts.push(link);
} else {
console.log();
console.log(`Not present: ${link.corporateUsername} ${retrievalError}`);
infoError = retrievalError;
}
infoError = retrievalError;
}
if (providers.corporateContactProvider && (info && info.userPrincipalName || link.corporateUsername)) {
try {
const userPrincipalName = info && info.userPrincipalName ? info.userPrincipalName : link.corporateUsername;
const contactsCache = await providers.corporateContactProvider.lookupContacts(userPrincipalName);
if (contactsCache || (!contactsCache && link.isServiceAccount)) {
bulkContacts.set(userPrincipalName, contactsCache);
}
} catch (identityServiceError) {
// Bulk cache is a secondary function of this job
console.warn(identityServiceError);
}
}
if (link.isServiceAccount) {
console.log(`skipping service account link ${link.corporateUsername}`);
console.log();
return;
}
try {
if (infoError) {
throw infoError;
}
if (!info || !info.manager) {
console.log(`No manager info is set for ${employeeDirectoryId} - ${info.displayName} ${info.userPrincipalName}`);
return; // no sleep
}
// Has the user's corporate display information changed?
let linkChanges = false;
if (info.displayName !== link.corporateDisplayName) {
linkChanges = true;
console.log(`Update to corporate link: display name changed from ${link.corporateDisplayName} to ${info.displayName}`);
link.corporateDisplayName = info.displayName;
}
if (info.userPrincipalName !== link.corporateUsername) {
linkChanges = true;
console.log(`Update to corporate link: username changed from ${link.corporateUsername} to ${info.userPrincipalName}`);
link.corporateUsername = info.disuserPrincipalNameplayName;
}
if (linkChanges) {
await linkProvider.updateLink(link);
console.log(`Updated link for ${link.corporateId}`);
}
if (!info.manager.mail) {
console.log('No manager mail address');
throw new Error('No manager mail address in graph');
}
const reducedWithManagerInfo: ICachedEmployeeInformation = {
id: info.id,
displayName: info.displayName,
userPrincipalName: info.userPrincipalName,
managerId: info.manager.id,
managerDisplayName: info.manager.displayName,
managerMail: info.manager.mail,
};
const key = `${RedisPrefixManagerInfoCache}${employeeDirectoryId}`;
const currentManagerIfAny = await cacheHelper.getObjectCompressed(key) as any;
if (!currentManagerIfAny) {
await cacheHelper.setObjectCompressedWithExpire(key, reducedWithManagerInfo, managerInfoCachePeriodMinutes);
++managerSets;
console.log(`Manager for ${reducedWithManagerInfo.displayName} set to ${reducedWithManagerInfo.managerDisplayName}`);
} else {
let updateEntry = false;
if (currentManagerIfAny.managerId !== reducedWithManagerInfo.managerId) {
updateEntry = true;
++managerUpdates;
console.log(`Manager for ${reducedWithManagerInfo.displayName} updated to ${reducedWithManagerInfo.managerDisplayName}`);
} else if (currentManagerIfAny.id !== reducedWithManagerInfo.id ||
currentManagerIfAny.displayName !== reducedWithManagerInfo.displayName ||
currentManagerIfAny.userPrincipalName !== reducedWithManagerInfo.userPrincipalName ||
currentManagerIfAny.managerDisplayName !== reducedWithManagerInfo.managerDisplayName ||
currentManagerIfAny.managerMail !== reducedWithManagerInfo.managerMail) {
updateEntry = true;
++managerMetadataUpdates;
console.log(`Metadata for ${reducedWithManagerInfo.displayName} updated`);
}
if (updateEntry) {
await cacheHelper.setObjectCompressedWithExpire(key, reducedWithManagerInfo, managerInfoCachePeriodMinutes);
}
}
} catch (retrievalError) {
if (retrievalError && retrievalError.status && retrievalError.status === 404) {
++notFoundErrors;
formerAccounts.push(link);
// Not deleting links so proactively: await linkProvider.deleteLink(link);
insights.trackEvent({ name: 'JobRefreshManagersNotFound', properties: { error: retrievalError.message } });
} else {
console.dir(retrievalError);
++errors;
insights.trackEvent({ name: 'JobRefreshManagersError', properties: { error: retrievalError.message } });
}
await sleep(secondsDelayAfterError * 1000);
return;
}
await sleep(secondsDelayAfterSuccess * 1000);
})));
console.log('All done with', errors, 'errors. Not found errors:', notFoundErrors);
console.dir(errorList);
console.log();
console.log(`Service Accounts not in the directory: ${unknownServiceAccounts.length}`);
console.log(unknownServiceAccounts.map(x => x.corporateUsername).sort().join('\n'));
console.log();
console.log(`Former accounts not in the directory: ${formerAccounts.length}`);
console.log(formerAccounts.map(x => x.corporateUsername).sort().join('\n'));
console.log();
if (bulkContacts.size) {
console.log(`Writing ${bulkContacts.size} contacts to bulk cache...`);
try {
await providers.corporateContactProvider.setBulkCachedContacts(bulkContacts);
console.log('Cached.');
} catch (cacheError) {
console.log('Cache problem:');
console.warn(cacheError);
}
}
console.log(`Manager updates: ${managerUpdates}`);
console.log(`Manager sets: ${managerSets}`);
console.log(`Other updates: ${managerMetadataUpdates}`);
console.log();
return {
successProperties: {
managerUpdates,
managerSets,
managerMetadataUpdates,
errors,
}
};
}