fix(server): decouple SDK client generation from workspace activation (#20514)

`activateWorkspace` enqueues SDK gen job inside
`WorkspaceManagerService.init()` introduced by
https://github.com/twentyhq/twenty/pull/19271

But if enqueue call fails it crashes cuz it doesn't have try catch so
created workspace is in corrupted state

<img width="636" height="812" alt="image"
src="https://github.com/user-attachments/assets/09acd042-46d0-4225-adc0-c74ea770785d"
/>


FIx:
Move SDK enqueue out of `init()` Call after
`activateAndInitializeUpgradeState` succeeds, wrap in try catch. Mirror
preInstalledAppsService.installOnWorkspace pattern.

Assuming enqueue failure if Redis is unavailable we fallback to
`SdkClientArchiveService.downloadArchiveBufferOrGenerate` which
generates it on the fly

Around 19 workspaces in prod affected with status `ONGOING_CREATION`
This commit is contained in:
neo773
2026-05-14 15:55:24 +05:30
committed by GitHub
parent dbc033b29b
commit 42975a4168
9 changed files with 197 additions and 38 deletions
@@ -5,13 +5,6 @@ import { Repository } from 'typeorm';
import { ApplicationService } from 'src/engine/core-modules/application/application.service';
import { FlatApplication } from 'src/engine/core-modules/application/types/flat-application.type';
import { InjectMessageQueue } from 'src/engine/core-modules/message-queue/decorators/message-queue.decorator';
import { MessageQueue } from 'src/engine/core-modules/message-queue/message-queue.constants';
import { MessageQueueService } from 'src/engine/core-modules/message-queue/services/message-queue.service';
import {
GenerateSdkClientJob,
GenerateSdkClientJobData,
} from 'src/engine/core-modules/sdk-client/jobs/generate-sdk-client.job';
import { UserWorkspaceEntity } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
import { RoleEntity } from 'src/engine/metadata-modules/role/role.entity';
@@ -37,8 +30,6 @@ export class WorkspaceManagerService {
@InjectRepository(RoleEntity)
private readonly roleRepository: Repository<RoleEntity>,
private readonly applicationService: ApplicationService,
@InjectMessageQueue(MessageQueue.workspaceQueue)
private readonly messageQueueService: MessageQueueService,
) {}
public async init({
@@ -83,34 +74,13 @@ export class WorkspaceManagerService {
`Metadata creation took ${dataSourceMetadataCreationEnd - dataSourceMetadataCreationStart}ms`,
);
const { workspaceCustomFlatApplication, twentyStandardFlatApplication } =
const { workspaceCustomFlatApplication } =
await this.applicationService.findWorkspaceTwentyStandardAndCustomApplicationOrThrow(
{
workspaceId,
},
);
await Promise.all([
this.messageQueueService.add<GenerateSdkClientJobData>(
GenerateSdkClientJob.name,
{
workspaceId,
applicationId: twentyStandardFlatApplication.id,
applicationUniversalIdentifier:
twentyStandardFlatApplication.universalIdentifier,
},
),
this.messageQueueService.add<GenerateSdkClientJobData>(
GenerateSdkClientJob.name,
{
workspaceId,
applicationId: workspaceCustomFlatApplication.id,
applicationUniversalIdentifier:
workspaceCustomFlatApplication.universalIdentifier,
},
),
]);
await this.setupDefaultRoles({
workspaceId,
userId,