From 19c07311664fd8f926dab526d4f900dcc4e4ac2b Mon Sep 17 00:00:00 2001 From: x032205 Date: Wed, 9 Jul 2025 19:54:35 -0400 Subject: [PATCH] Add jitter and increase window to 12 m --- .../20250602155451_fix-secret-versions.ts | 2 +- .../org-membership/org-membership-dal.ts | 6 +-- backend/src/services/org/org-service.ts | 41 ++++++++++++------- 3 files changed, 31 insertions(+), 18 deletions(-) diff --git a/backend/src/db/migrations/20250602155451_fix-secret-versions.ts b/backend/src/db/migrations/20250602155451_fix-secret-versions.ts index ace1895de..0fb23e327 100644 --- a/backend/src/db/migrations/20250602155451_fix-secret-versions.ts +++ b/backend/src/db/migrations/20250602155451_fix-secret-versions.ts @@ -3,7 +3,7 @@ import { Knex } from "knex"; import { chunkArray } from "@app/lib/fn"; import { selectAllTableCols } from "@app/lib/knex"; -import { logger, initLogger } from "@app/lib/logger"; +import { initLogger, logger } from "@app/lib/logger"; import { SecretType, TableName } from "../schemas"; diff --git a/backend/src/services/org-membership/org-membership-dal.ts b/backend/src/services/org-membership/org-membership-dal.ts index ebf1700d0..ed4867025 100644 --- a/backend/src/services/org-membership/org-membership-dal.ts +++ b/backend/src/services/org-membership/org-membership-dal.ts @@ -108,16 +108,16 @@ export const orgMembershipDALFactory = (db: TDbClient) => { const now = new Date(); const oneWeekAgo = new Date(now.getTime() - 7 * 24 * 60 * 60 * 1000); const oneMonthAgo = new Date(now.getTime() - 30 * 24 * 60 * 60 * 1000); - const threeMonthsAgo = new Date(now.getTime() - 90 * 24 * 60 * 60 * 1000); + const twelveMonthsAgo = new Date(now.getTime() - 360 * 24 * 60 * 60 * 1000); const memberships = await db .replicaNode()(TableName.OrgMembership) .where("status", "invited") .where((qb) => { - // lastInvitedAt is null AND createdAt is between 1 week and 3 months ago + // lastInvitedAt is null AND createdAt is between 1 week and 12 months ago void qb .whereNull(`${TableName.OrgMembership}.lastInvitedAt`) - .whereBetween(`${TableName.OrgMembership}.createdAt`, [threeMonthsAgo, oneWeekAgo]); + .whereBetween(`${TableName.OrgMembership}.createdAt`, [twelveMonthsAgo, oneWeekAgo]); }) .orWhere((qb) => { // lastInvitedAt is older than 1 week ago AND createdAt is younger than 1 month ago diff --git a/backend/src/services/org/org-service.ts b/backend/src/services/org/org-service.ts index 5941eb013..8917a4fc1 100644 --- a/backend/src/services/org/org-service.ts +++ b/backend/src/services/org/org-service.ts @@ -36,6 +36,8 @@ import { getConfig } from "@app/lib/config/env"; import { generateAsymmetricKeyPair } from "@app/lib/crypto"; import { generateSymmetricKey, infisicalSymmetricDecrypt, infisicalSymmetricEncypt } from "@app/lib/crypto/encryption"; import { generateUserSrpKeys } from "@app/lib/crypto/srp"; +import { applyJitter } from "@app/lib/dates"; +import { delay as delayMs } from "@app/lib/delay"; import { BadRequestError, ForbiddenRequestError, @@ -44,9 +46,10 @@ import { UnauthorizedError } from "@app/lib/errors"; import { groupBy } from "@app/lib/fn"; +import { logger } from "@app/lib/logger"; import { alphaNumericNanoId } from "@app/lib/nanoid"; import { isDisposableEmail } from "@app/lib/validator"; -import { TQueueServiceFactory } from "@app/queue"; +import { QueueName, TQueueServiceFactory } from "@app/queue"; import { getDefaultOrgMembershipRoleForUpdateOrg } from "@app/services/org/org-role-fns"; import { TOrgMembershipDALFactory } from "@app/services/org-membership/org-membership-dal"; import { TUserAliasDALFactory } from "@app/services/user-alias/user-alias-dal"; @@ -1438,6 +1441,8 @@ export const orgServiceFactory = ({ * Re-send emails to users who haven't accepted an invite yet */ const notifyInvitedUsers = async () => { + logger.info(`${QueueName.DailyResourceCleanUp}: notify invited users started`); + const invitedUsers = await orgMembershipDAL.findRecentInvitedMemberships(); const appCfg = getConfig(); @@ -1461,24 +1466,32 @@ export const orgServiceFactory = ({ }); if (invitedUser.inviteEmail) { - await smtpService.sendMail({ - template: SmtpTemplates.OrgInvite, - subjectLine: `Reminder: You have been invited to ${org.name} on Infisical`, - recipients: [invitedUser.inviteEmail], - substitutions: { - organizationName: org.name, - email: invitedUser.inviteEmail, - organizationId: org.id.toString(), - token, - callback_url: `${appCfg.SITE_URL}/signupinvite` - } - }); - notifiedUsers.push(invitedUser.id); + await delayMs(Math.max(0, applyJitter(0, 2000))); + + try { + await smtpService.sendMail({ + template: SmtpTemplates.OrgInvite, + subjectLine: `Reminder: You have been invited to ${org.name} on Infisical`, + recipients: [invitedUser.inviteEmail], + substitutions: { + organizationName: org.name, + email: invitedUser.inviteEmail, + organizationId: org.id.toString(), + token, + callback_url: `${appCfg.SITE_URL}/signupinvite` + } + }); + notifiedUsers.push(invitedUser.id); + } catch (err) { + logger.error(err, `${QueueName.DailyResourceCleanUp}: notify invited users failed to send email`); + } } }) ); await orgMembershipDAL.updateLastInvitedAtByIds(notifiedUsers); + + logger.info(`${QueueName.DailyResourceCleanUp}: notify invited users completed`); }; return {