perf(onboarding): compute invite suggestions on-demand (#21696)
## Summary Follow-up to #21640. In production, invite suggestions took ~1 minute to appear because `FetchOnboardingInviteSuggestionsJob` ran on the shared `calendarQueue` behind heavy calendar-sync jobs. - **Drop the background job entirely.** `getInviteSuggestions` now resolves the connected account from the authenticated `@AuthUserWorkspaceId()` and computes suggestions on demand: cache-first, with a bounded calendar fetch + cache write on a miss. Removes the Google/Microsoft enqueues, the `shouldComputeInviteSuggestions` threading through the auth controllers, and the now-unused `shouldComputeInviteSuggestionsOnConnect` / `isOnboardingConnectAccountPending` helpers. - **Prefetch one step earlier.** New `usePrefetchInviteSuggestions` hook fires the query from `CreateProfile` so the server cache is warm by the time the invite step renders. `InviteTeam` switches from `network-only` → `cache-first`. If the profile step is skipped, the invite step still computes on-demand (~1–3s, no queue) — no more minute-long waits. No GraphQL schema change. ## Test plan - [ ] Connect Google calendar in onboarding → invite step renders prefilled teammates with no perceivable wait - [ ] Connect Microsoft calendar in onboarding → same - [ ] Onboard with workspace name already set so profile step is skipped → invite step still prefills (just with a brief on-demand fetch instead of 1 min) - [ ] Connect a non-work-email account → invite step renders empty form (no suggestions) - [ ] `npx nx typecheck twenty-server` ✅ - [ ] `npx nx lint:diff-with-main twenty-server` ✅ - [ ] `npx nx lint:diff-with-main twenty-front` ✅ (changed files clean) - [ ] `google-apis.service.spec.ts` + `microsoft-apis.service.spec.ts` pass https://claude.ai/code/session_019MyY3bfAEij4AwSXMCLtWY --- _Generated by [Claude Code](https://claude.ai/code/session_019MyY3bfAEij4AwSXMCLtWY)_ <!-- This is an auto-generated description by cubic. --> <a href="https://cubic.dev/pr/twentyhq/twenty/pull/21696?utm_source=github" target="_blank" rel="noopener noreferrer" data-no-image-dialog="true"><picture><source media="(prefers-color-scheme: dark)" srcset="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"><source media="(prefers-color-scheme: light)" srcset="https://www.cubic.dev/buttons/review-in-cubic-light.svg"><img alt="Review in cubic" src="https://www.cubic.dev/buttons/review-in-cubic-dark.svg"></picture></a> <!-- End of auto-generated description by cubic. --> Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
-7
@@ -98,12 +98,6 @@ export class GoogleAPIsAuthController {
|
||||
|
||||
const handle = emails[0].value.toLowerCase();
|
||||
|
||||
const shouldComputeInviteSuggestions =
|
||||
await this.onboardingService.shouldComputeInviteSuggestionsOnConnect({
|
||||
userId,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const connectedAccountId =
|
||||
await this.googleAPIsService.refreshGoogleRefreshToken({
|
||||
handle,
|
||||
@@ -115,7 +109,6 @@ export class GoogleAPIsAuthController {
|
||||
calendarVisibility,
|
||||
messageVisibility,
|
||||
skipMessageChannelConfiguration,
|
||||
shouldComputeInviteSuggestions,
|
||||
});
|
||||
|
||||
if (userId) {
|
||||
|
||||
-7
@@ -105,12 +105,6 @@ export class MicrosoftAPIsAuthController {
|
||||
|
||||
const handle = emails[0].value.toLowerCase();
|
||||
|
||||
const shouldComputeInviteSuggestions =
|
||||
await this.onboardingService.shouldComputeInviteSuggestionsOnConnect({
|
||||
userId,
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
const connectedAccountId =
|
||||
await this.microsoftAPIsService.refreshMicrosoftRefreshToken({
|
||||
handle,
|
||||
@@ -122,7 +116,6 @@ export class MicrosoftAPIsAuthController {
|
||||
calendarVisibility,
|
||||
messageVisibility,
|
||||
skipMessageChannelConfiguration,
|
||||
shouldComputeInviteSuggestions,
|
||||
});
|
||||
|
||||
if (userId) {
|
||||
|
||||
@@ -47,10 +47,6 @@ import {
|
||||
MessagingMessageListFetchJob,
|
||||
type MessagingMessageListFetchJobData,
|
||||
} from 'src/modules/messaging/message-import-manager/jobs/messaging-message-list-fetch.job';
|
||||
import {
|
||||
FetchOnboardingInviteSuggestionsJob,
|
||||
type FetchOnboardingInviteSuggestionsJobData,
|
||||
} from 'src/modules/onboarding-invite-suggestions/jobs/fetch-onboarding-invite-suggestions.job';
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
@Injectable()
|
||||
@@ -93,7 +89,6 @@ export class GoogleAPIsService {
|
||||
calendarVisibility: CalendarChannelVisibility | undefined;
|
||||
messageVisibility: MessageChannelVisibility | undefined;
|
||||
skipMessageChannelConfiguration?: boolean;
|
||||
shouldComputeInviteSuggestions?: boolean;
|
||||
}): Promise<string> {
|
||||
const {
|
||||
handle,
|
||||
@@ -103,7 +98,6 @@ export class GoogleAPIsService {
|
||||
calendarVisibility,
|
||||
messageVisibility,
|
||||
skipMessageChannelConfiguration,
|
||||
shouldComputeInviteSuggestions,
|
||||
} = input;
|
||||
|
||||
const isCalendarEnabled = this.twentyConfigService.get(
|
||||
@@ -353,23 +347,6 @@ export class GoogleAPIsService {
|
||||
}
|
||||
}
|
||||
|
||||
if (
|
||||
shouldComputeInviteSuggestions &&
|
||||
isCalendarEnabled &&
|
||||
isCalendarAvailable
|
||||
) {
|
||||
void this.calendarQueueService
|
||||
.add<FetchOnboardingInviteSuggestionsJobData>(
|
||||
FetchOnboardingInviteSuggestionsJob.name,
|
||||
{
|
||||
workspaceId,
|
||||
userId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
},
|
||||
)
|
||||
.catch(() => undefined);
|
||||
}
|
||||
|
||||
return newOrExistingConnectedAccountId;
|
||||
},
|
||||
authContext,
|
||||
|
||||
-22
@@ -39,10 +39,6 @@ import {
|
||||
import { CalendarChannelSyncStatusService } from 'src/modules/calendar/common/services/calendar-channel-sync-status.service';
|
||||
import { EmailAliasManagerService } from 'src/modules/connected-account/email-alias-manager/services/email-alias-manager.service';
|
||||
import { AccountsToReconnectService } from 'src/modules/connected-account/services/accounts-to-reconnect.service';
|
||||
import {
|
||||
FetchOnboardingInviteSuggestionsJob,
|
||||
type FetchOnboardingInviteSuggestionsJobData,
|
||||
} from 'src/modules/onboarding-invite-suggestions/jobs/fetch-onboarding-invite-suggestions.job';
|
||||
|
||||
import { MessageChannelSyncStatusService } from 'src/modules/messaging/common/services/message-channel-sync-status.service';
|
||||
import {
|
||||
@@ -89,7 +85,6 @@ export class MicrosoftAPIsService {
|
||||
calendarVisibility: CalendarChannelVisibility | undefined;
|
||||
messageVisibility: MessageChannelVisibility | undefined;
|
||||
skipMessageChannelConfiguration?: boolean;
|
||||
shouldComputeInviteSuggestions?: boolean;
|
||||
}): Promise<string> {
|
||||
const {
|
||||
handle,
|
||||
@@ -99,7 +94,6 @@ export class MicrosoftAPIsService {
|
||||
calendarVisibility,
|
||||
messageVisibility,
|
||||
skipMessageChannelConfiguration,
|
||||
shouldComputeInviteSuggestions,
|
||||
} = input;
|
||||
|
||||
const scopes = getMicrosoftApisOauthScopes();
|
||||
@@ -316,22 +310,6 @@ export class MicrosoftAPIsService {
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
if (
|
||||
shouldComputeInviteSuggestions &&
|
||||
syncableCalendarChannels.length > 0
|
||||
) {
|
||||
void this.calendarQueueService
|
||||
.add<FetchOnboardingInviteSuggestionsJobData>(
|
||||
FetchOnboardingInviteSuggestionsJob.name,
|
||||
{
|
||||
workspaceId,
|
||||
userId,
|
||||
connectedAccountId: newOrExistingConnectedAccountId,
|
||||
},
|
||||
)
|
||||
.catch(() => undefined);
|
||||
}
|
||||
}
|
||||
|
||||
return newOrExistingConnectedAccountId;
|
||||
|
||||
Reference in New Issue
Block a user