Skip to content

Commit

Permalink
fix(core): Flush instance stopped event immediately (#10238)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomi authored and cstuncsik committed Aug 1, 2024
1 parent edeb633 commit 0667831
Show file tree
Hide file tree
Showing 21 changed files with 224 additions and 275 deletions.
171 changes: 65 additions & 106 deletions packages/cli/src/InternalHooks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,49 +43,41 @@ export class InternalHooks {
private readonly projectRelationRepository: ProjectRelationRepository,
private readonly _eventBus: MessageEventBus, // needed until we decouple telemetry
) {
workflowStatisticsService.on(
'telemetry.onFirstProductionWorkflowSuccess',
async (metrics) => await this.onFirstProductionWorkflowSuccess(metrics),
workflowStatisticsService.on('telemetry.onFirstProductionWorkflowSuccess', (metrics) =>
this.onFirstProductionWorkflowSuccess(metrics),
);
workflowStatisticsService.on(
'telemetry.onFirstWorkflowDataLoad',
async (metrics) => await this.onFirstWorkflowDataLoad(metrics),
workflowStatisticsService.on('telemetry.onFirstWorkflowDataLoad', (metrics) =>
this.onFirstWorkflowDataLoad(metrics),
);
}

async init() {
await this.telemetry.init();
}

async onFrontendSettingsAPI(pushRef?: string): Promise<void> {
return await this.telemetry.track('Session started', { session_id: pushRef });
onFrontendSettingsAPI(pushRef?: string): void {
this.telemetry.track('Session started', { session_id: pushRef });
}

async onPersonalizationSurveySubmitted(
userId: string,
answers: Record<string, string>,
): Promise<void> {
onPersonalizationSurveySubmitted(userId: string, answers: Record<string, string>): void {
const camelCaseKeys = Object.keys(answers);
const personalizationSurveyData = { user_id: userId } as Record<string, string | string[]>;
camelCaseKeys.forEach((camelCaseKey) => {
personalizationSurveyData[snakeCase(camelCaseKey)] = answers[camelCaseKey];
});

return await this.telemetry.track(
'User responded to personalization questions',
personalizationSurveyData,
);
this.telemetry.track('User responded to personalization questions', personalizationSurveyData);
}

async onWorkflowCreated(
onWorkflowCreated(
user: User,
workflow: IWorkflowBase,
project: Project,
publicApi: boolean,
): Promise<void> {
): void {
const { nodeGraph } = TelemetryHelpers.generateNodesGraph(workflow, this.nodeTypes);

void this.telemetry.track('User created workflow', {
this.telemetry.track('User created workflow', {
user_id: user.id,
workflow_id: workflow.id,
node_graph_string: JSON.stringify(nodeGraph),
Expand All @@ -95,8 +87,8 @@ export class InternalHooks {
});
}

async onWorkflowDeleted(user: User, workflowId: string, publicApi: boolean): Promise<void> {
void this.telemetry.track('User deleted workflow', {
onWorkflowDeleted(user: User, workflowId: string, publicApi: boolean): void {
this.telemetry.track('User deleted workflow', {
user_id: user.id,
workflow_id: workflowId,
public_api: publicApi,
Expand Down Expand Up @@ -136,7 +128,7 @@ export class InternalHooks {
(note) => note.overlapping,
).length;

void this.telemetry.track('User saved workflow', {
this.telemetry.track('User saved workflow', {
user_id: user.id,
workflow_id: workflow.id,
node_graph_string: JSON.stringify(nodeGraph),
Expand All @@ -155,7 +147,7 @@ export class InternalHooks {
workflow: IWorkflowBase,
runData?: IRun,
userId?: string,
): Promise<void> {
) {
if (!workflow.id) {
return;
}
Expand All @@ -165,8 +157,6 @@ export class InternalHooks {
return;
}

const promises = [];

const telemetryProperties: IExecutionTrackProperties = {
workflow_id: workflow.id,
is_manual: false,
Expand Down Expand Up @@ -270,7 +260,7 @@ export class InternalHooks {
node_id: nodeGraphResult.nameIndices[runData.data.startData?.destinationNode],
};

promises.push(this.telemetry.track('Manual node exec finished', telemetryPayload));
this.telemetry.track('Manual node exec finished', telemetryPayload);
} else {
nodeGraphResult.webhookNodeNames.forEach((name: string) => {
const execJson = runData.data.resultData.runData[name]?.[0]?.data?.main?.[0]?.[0]
Expand All @@ -282,56 +272,52 @@ export class InternalHooks {
}
});

promises.push(
this.telemetry.track('Manual workflow exec finished', manualExecEventProperties),
);
this.telemetry.track('Manual workflow exec finished', manualExecEventProperties);
}
}
}

void Promise.all([...promises, this.telemetry.trackWorkflowExecution(telemetryProperties)]);
this.telemetry.trackWorkflowExecution(telemetryProperties);
}

async onWorkflowSharingUpdate(workflowId: string, userId: string, userList: string[]) {
onWorkflowSharingUpdate(workflowId: string, userId: string, userList: string[]) {
const properties: ITelemetryTrackProperties = {
workflow_id: workflowId,
user_id_sharer: userId,
user_id_list: userList,
};

return await this.telemetry.track('User updated workflow sharing', properties);
this.telemetry.track('User updated workflow sharing', properties);
}

async onN8nStop(): Promise<void> {
const timeoutPromise = new Promise<void>((resolve) => {
setTimeout(() => {
resolve();
}, 3000);
setTimeout(resolve, 3000);
});

return await Promise.race([timeoutPromise, this.telemetry.trackN8nStop()]);
}

async onUserDeletion(userDeletionData: {
onUserDeletion(userDeletionData: {
user: User;
telemetryData: ITelemetryUserDeletionData;
publicApi: boolean;
}): Promise<void> {
void this.telemetry.track('User deleted user', {
}) {
this.telemetry.track('User deleted user', {
...userDeletionData.telemetryData,
user_id: userDeletionData.user.id,
public_api: userDeletionData.publicApi,
});
}

async onUserInvite(userInviteData: {
onUserInvite(userInviteData: {
user: User;
target_user_id: string[];
public_api: boolean;
email_sent: boolean;
invitee_role: string;
}): Promise<void> {
void this.telemetry.track('User invited new user', {
}) {
this.telemetry.track('User invited new user', {
user_id: userInviteData.user.id,
target_user_id: userInviteData.target_user_id,
public_api: userInviteData.public_api,
Expand All @@ -340,82 +326,61 @@ export class InternalHooks {
});
}

async onUserRoleChange(userRoleChangeData: {
onUserRoleChange(userRoleChangeData: {
user: User;
target_user_id: string;
public_api: boolean;
target_user_new_role: string;
}) {
const { user, ...rest } = userRoleChangeData;

void this.telemetry.track('User changed role', { user_id: user.id, ...rest });
this.telemetry.track('User changed role', { user_id: user.id, ...rest });
}

async onUserRetrievedUser(userRetrievedData: {
user_id: string;
public_api: boolean;
}): Promise<void> {
return await this.telemetry.track('User retrieved user', userRetrievedData);
onUserRetrievedUser(userRetrievedData: { user_id: string; public_api: boolean }) {
this.telemetry.track('User retrieved user', userRetrievedData);
}

async onUserRetrievedAllUsers(userRetrievedData: {
user_id: string;
public_api: boolean;
}): Promise<void> {
return await this.telemetry.track('User retrieved all users', userRetrievedData);
onUserRetrievedAllUsers(userRetrievedData: { user_id: string; public_api: boolean }) {
this.telemetry.track('User retrieved all users', userRetrievedData);
}

async onUserRetrievedExecution(userRetrievedData: {
user_id: string;
public_api: boolean;
}): Promise<void> {
return await this.telemetry.track('User retrieved execution', userRetrievedData);
onUserRetrievedExecution(userRetrievedData: { user_id: string; public_api: boolean }) {
this.telemetry.track('User retrieved execution', userRetrievedData);
}

async onUserRetrievedAllExecutions(userRetrievedData: {
user_id: string;
public_api: boolean;
}): Promise<void> {
return await this.telemetry.track('User retrieved all executions', userRetrievedData);
onUserRetrievedAllExecutions(userRetrievedData: { user_id: string; public_api: boolean }) {
this.telemetry.track('User retrieved all executions', userRetrievedData);
}

async onUserRetrievedWorkflow(userRetrievedData: {
user_id: string;
public_api: boolean;
}): Promise<void> {
return await this.telemetry.track('User retrieved workflow', userRetrievedData);
onUserRetrievedWorkflow(userRetrievedData: { user_id: string; public_api: boolean }) {
this.telemetry.track('User retrieved workflow', userRetrievedData);
}

async onUserRetrievedAllWorkflows(userRetrievedData: {
user_id: string;
public_api: boolean;
}): Promise<void> {
return await this.telemetry.track('User retrieved all workflows', userRetrievedData);
onUserRetrievedAllWorkflows(userRetrievedData: { user_id: string; public_api: boolean }) {
this.telemetry.track('User retrieved all workflows', userRetrievedData);
}

async onUserUpdate(userUpdateData: { user: User; fields_changed: string[] }): Promise<void> {
void this.telemetry.track('User changed personal settings', {
onUserUpdate(userUpdateData: { user: User; fields_changed: string[] }) {
this.telemetry.track('User changed personal settings', {
user_id: userUpdateData.user.id,
fields_changed: userUpdateData.fields_changed,
});
}

async onUserInviteEmailClick(userInviteClickData: {
inviter: User;
invitee: User;
}): Promise<void> {
void this.telemetry.track('User clicked invite link from email', {
onUserInviteEmailClick(userInviteClickData: { inviter: User; invitee: User }) {
this.telemetry.track('User clicked invite link from email', {
user_id: userInviteClickData.invitee.id,
});
}

async onUserPasswordResetEmailClick(userPasswordResetData: { user: User }): Promise<void> {
void this.telemetry.track('User clicked password reset link from email', {
onUserPasswordResetEmailClick(userPasswordResetData: { user: User }) {
this.telemetry.track('User clicked password reset link from email', {
user_id: userPasswordResetData.user.id,
});
}

async onUserTransactionalEmail(userTransactionalEmailData: {
onUserTransactionalEmail(userTransactionalEmailData: {
user_id: string;
message_type:
| 'Reset password'
Expand All @@ -424,37 +389,34 @@ export class InternalHooks {
| 'Workflow shared'
| 'Credentials shared';
public_api: boolean;
}): Promise<void> {
return await this.telemetry.track(
'Instance sent transactional email to user',
userTransactionalEmailData,
);
}) {
this.telemetry.track('Instance sent transactional email to user', userTransactionalEmailData);
}

async onUserPasswordResetRequestClick(userPasswordResetData: { user: User }): Promise<void> {
void this.telemetry.track('User requested password reset while logged out', {
onUserPasswordResetRequestClick(userPasswordResetData: { user: User }) {
this.telemetry.track('User requested password reset while logged out', {
user_id: userPasswordResetData.user.id,
});
}

async onInstanceOwnerSetup(instanceOwnerSetupData: { user_id: string }): Promise<void> {
return await this.telemetry.track('Owner finished instance setup', instanceOwnerSetupData);
onInstanceOwnerSetup(instanceOwnerSetupData: { user_id: string }) {
this.telemetry.track('Owner finished instance setup', instanceOwnerSetupData);
}

async onUserSignup(
onUserSignup(
user: User,
userSignupData: {
user_type: AuthProviderType;
was_disabled_ldap_user: boolean;
},
): Promise<void> {
void this.telemetry.track('User signed up', {
) {
this.telemetry.track('User signed up', {
user_id: user.id,
...userSignupData,
});
}

async onEmailFailed(failedEmailData: {
onEmailFailed(failedEmailData: {
user: User;
message_type:
| 'Reset password'
Expand All @@ -463,30 +425,27 @@ export class InternalHooks {
| 'Workflow shared'
| 'Credentials shared';
public_api: boolean;
}): Promise<void> {
void this.telemetry.track('Instance failed to send transactional email to user', {
}) {
this.telemetry.track('Instance failed to send transactional email to user', {
user_id: failedEmailData.user.id,
});
}

/*
* Execution Statistics
*/
async onFirstProductionWorkflowSuccess(data: {
user_id: string;
workflow_id: string;
}): Promise<void> {
return await this.telemetry.track('Workflow first prod success', data);
onFirstProductionWorkflowSuccess(data: { user_id: string; workflow_id: string }) {
this.telemetry.track('Workflow first prod success', data);
}

async onFirstWorkflowDataLoad(data: {
onFirstWorkflowDataLoad(data: {
user_id: string;
workflow_id: string;
node_type: string;
node_id: string;
credential_type?: string;
credential_id?: string;
}): Promise<void> {
return await this.telemetry.track('Workflow first data fetched', data);
}) {
this.telemetry.track('Workflow first data fetched', data);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export = {
return res.status(404).json({ message: 'Not Found' });
}

void Container.get(InternalHooks).onUserRetrievedExecution({
Container.get(InternalHooks).onUserRetrievedExecution({
user_id: req.user.id,
public_api: true,
});
Expand Down Expand Up @@ -129,7 +129,7 @@ export = {
const count =
await Container.get(ExecutionRepository).getExecutionsCountForPublicApi(filters);

void Container.get(InternalHooks).onUserRetrievedAllExecutions({
Container.get(InternalHooks).onUserRetrievedAllExecutions({
user_id: req.user.id,
public_api: true,
});
Expand Down
Loading

0 comments on commit 0667831

Please sign in to comment.