Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Increase running timer to 45 seconds and catch errors around batchIterateEntities #250

Merged
merged 2 commits into from Mar 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/steps/account.ts
Expand Up @@ -32,7 +32,7 @@ export async function fetchAccountDetails({
}: IntegrationStepExecutionContext<IntegrationConfig>) {
let stepAnnouncer;
if (accountFlagged) {
stepAnnouncer = new StepAnnouncer(Steps.ACCOUNT, 10, logger);
stepAnnouncer = new StepAnnouncer(Steps.ACCOUNT, logger);
}

const apiClient = createAPIClient(instance.config, logger);
Expand Down
2 changes: 1 addition & 1 deletion src/steps/applicationCreation.ts
Expand Up @@ -18,7 +18,7 @@ export async function buildUserCreatedApplication({
}: IntegrationStepExecutionContext<IntegrationConfig>) {
let stepAnnouncer;
if (accountFlagged) {
stepAnnouncer = new StepAnnouncer(Steps.APPLICATION_CREATION, 10, logger);
stepAnnouncer = new StepAnnouncer(Steps.APPLICATION_CREATION, logger);
}

const apiClient = createAPIClient(instance.config, logger);
Expand Down
2 changes: 1 addition & 1 deletion src/steps/applications.ts
Expand Up @@ -31,7 +31,7 @@ export async function fetchApplications({
}: IntegrationStepExecutionContext<IntegrationConfig>) {
let stepAnnouncer;
if (accountFlagged) {
stepAnnouncer = new StepAnnouncer(Steps.APPLICATIONS, 10, logger);
stepAnnouncer = new StepAnnouncer(Steps.APPLICATIONS, logger);
}

const apiClient = createAPIClient(instance.config, logger);
Expand Down
2 changes: 1 addition & 1 deletion src/steps/devices.ts
Expand Up @@ -26,7 +26,7 @@ export async function fetchDevices({
}: IntegrationStepExecutionContext<IntegrationConfig>) {
let stepAnnouncer;
if (accountFlagged) {
stepAnnouncer = new StepAnnouncer(Steps.DEVICES, 10, logger);
stepAnnouncer = new StepAnnouncer(Steps.DEVICES, logger);
}

const apiClient = createAPIClient(instance.config, logger);
Expand Down
2 changes: 1 addition & 1 deletion src/steps/factorDevices.ts
Expand Up @@ -19,7 +19,7 @@ export async function fetchFactorDevices({
}: IntegrationStepExecutionContext<IntegrationConfig>) {
let stepAnnouncer;
if (accountFlagged) {
stepAnnouncer = new StepAnnouncer(Steps.MFA_DEVICES, 10, logger);
stepAnnouncer = new StepAnnouncer(Steps.MFA_DEVICES, logger);
}

const apiClient = createAPIClient(instance.config, logger);
Expand Down
41 changes: 21 additions & 20 deletions src/steps/groups.ts
Expand Up @@ -34,7 +34,7 @@ export async function fetchGroups({
}: IntegrationStepExecutionContext<IntegrationConfig>) {
let stepAnnouncer;
if (accountFlagged) {
stepAnnouncer = new StepAnnouncer(Steps.GROUPS, 10, logger);
stepAnnouncer = new StepAnnouncer(Steps.GROUPS, logger);
}

const apiClient = createAPIClient(instance.config, logger);
Expand Down Expand Up @@ -96,7 +96,6 @@ export async function buildAppUserGroupUserRelationships(
if (accountFlagged) {
stepAnnouncer = new StepAnnouncer(
Steps.APP_USER_GROUP_USERS_RELATIONSHIP,
10,
context.logger,
);
}
Expand All @@ -117,7 +116,6 @@ export async function buildUserGroupUserRelationships(
if (accountFlagged) {
stepAnnouncer = new StepAnnouncer(
Steps.USER_GROUP_USERS_RELATIONSHIP,
10,
context.logger,
);
}
Expand All @@ -137,7 +135,6 @@ async function buildGroupEntityToUserRelationships(
if (accountFlagged) {
stepAnnouncer = new StepAnnouncer(
Steps.APP_USER_GROUP_USERS_RELATIONSHIP,
10,
context.logger,
);
}
Expand Down Expand Up @@ -186,23 +183,27 @@ async function buildGroupEntityToUserRelationships(
}
}

await batchIterateEntities({
context,
batchSize: 1000,
filter: { _type: groupEntityType },
async iteratee(groupEntities) {
const usersForGroupEntities = await collectUsersForGroupEntities(
apiClient,
groupEntities,
);

for (const { groupEntity, users } of usersForGroupEntities) {
for (const user of users) {
await createGroupUserRelationshipWithJob(groupEntity, user);
try {
await batchIterateEntities({
context,
batchSize: 1000,
filter: { _type: groupEntityType },
async iteratee(groupEntities) {
const usersForGroupEntities = await collectUsersForGroupEntities(
apiClient,
groupEntities,
);

for (const { groupEntity, users } of usersForGroupEntities) {
for (const user of users) {
await createGroupUserRelationshipWithJob(groupEntity, user);
}
}
}
},
});
},
});
} catch (err) {
logger.error({ err }, 'Failed to build group to user relationships');
}

if (accountFlagged) {
stepAnnouncer.finish();
Expand Down
2 changes: 1 addition & 1 deletion src/steps/roles.ts
Expand Up @@ -53,7 +53,7 @@ export async function fetchRoles({
}: IntegrationStepExecutionContext<IntegrationConfig>) {
let stepAnnouncer;
if (accountFlagged) {
stepAnnouncer = new StepAnnouncer(Steps.ROLES, 10, logger);
stepAnnouncer = new StepAnnouncer(Steps.ROLES, logger);
}

const apiClient = createAPIClient(instance.config, logger);
Expand Down
2 changes: 1 addition & 1 deletion src/steps/rules.ts
Expand Up @@ -26,7 +26,7 @@ export async function fetchRules({
}: IntegrationStepExecutionContext<IntegrationConfig>) {
let stepAnnouncer;
if (accountFlagged) {
stepAnnouncer = new StepAnnouncer(Steps.RULES, 10, logger);
stepAnnouncer = new StepAnnouncer(Steps.RULES, logger);
}

const apiClient = createAPIClient(instance.config, logger);
Expand Down
2 changes: 1 addition & 1 deletion src/steps/users.ts
Expand Up @@ -26,7 +26,7 @@ export async function fetchUsers({
}: IntegrationStepExecutionContext<IntegrationConfig>) {
let stepAnnouncer;
if (accountFlagged) {
stepAnnouncer = new StepAnnouncer(Steps.USERS, 10, logger);
stepAnnouncer = new StepAnnouncer(Steps.USERS, logger);
}

const apiClient = createAPIClient(instance.config, logger);
Expand Down
56 changes: 29 additions & 27 deletions src/util/runningTimer.ts
@@ -1,7 +1,4 @@
import {
IntegrationInfoEventName,
IntegrationLogger,
} from '@jupiterone/integration-sdk-core';
import { IntegrationLogger } from '@jupiterone/integration-sdk-core';

class StepAnnouncer {
private stepId: string;
Expand All @@ -12,58 +9,63 @@ class StepAnnouncer {

constructor(
stepId: string,
announceEvery: number,
logger: IntegrationLogger,
announceEvery: number = 45,
) {
this.stepId = stepId;
this.announceEvery = announceEvery * 1000; // Keep milliseconds for JS timers
this.announceEvery = announceEvery * 1000;
this.logger = logger;
this.startedAt = new Date();
this.start(); // Consider starting outside of the constructor for more control
this.start();
}

private getReadableHumanTime(): string {
const elapsedSeconds = Math.floor(
(new Date().getTime() - this.startedAt.getTime()) / 1000,
);
const minutes = Math.floor(elapsedSeconds / 60);
const hours = Math.floor(elapsedSeconds / 3600);
const remainingMinutes = Math.floor((elapsedSeconds % 3600) / 60);
const remainingSeconds = elapsedSeconds % 60;
let message =
minutes > 0 ? `${minutes} minute${minutes > 1 ? 's' : ''}` : '';
if (remainingSeconds > 0) {
message += message
? ` ${remainingSeconds} second${remainingSeconds > 1 ? 's' : ''}`
: `${remainingSeconds} second${remainingSeconds > 1 ? 's' : ''}`;

const messageParts: string[] = [];

if (hours > 0) {
messageParts.push(`${hours} hour${hours > 1 ? 's' : ''}`);
}
if (remainingMinutes > 0) {
messageParts.push(
`${remainingMinutes} minute${remainingMinutes > 1 ? 's' : ''}`,
);
}
return message || '0 seconds';
if (remainingSeconds > 0 || messageParts.length === 0) {
messageParts.push(
`${remainingSeconds} second${remainingSeconds > 1 ? 's' : ''}`,
);
}

return messageParts.join(' ');
}

public start(): void {
if (this.intervalId === null) {
this.intervalId = setInterval(() => this.announce(), this.announceEvery);
this.logger.publishInfoEvent({
description: `[${this.stepId}] has started.`,
name: IntegrationInfoEventName.Stats,
});
this.logger.info(`[${this.stepId}] has started.`);
}
}

private announce(): void {
const timeMessage = this.getReadableHumanTime();
this.logger.publishInfoEvent({
description: `[${this.stepId}] has been running for ${timeMessage}.`,
name: IntegrationInfoEventName.Stats,
});
const description = `[${this.stepId}] has been running for ${timeMessage}.`;
this.logger.info(description);
}

public finish(): void {
if (this.intervalId !== null) {
clearInterval(this.intervalId);
this.intervalId = null;
this.logger.publishInfoEvent({
description: `[${this.stepId}] has finished after ${this.getReadableHumanTime()}.`,
name: IntegrationInfoEventName.Stats,
});

const description = `[${this.stepId}] has finished after ${this.getReadableHumanTime()}.`;
this.logger.info(description);
}
}
}
Expand Down