Skip to content

Improve performance on metadata computation #12785

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

Merged
merged 24 commits into from
Jun 23, 2025
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -140,7 +140,6 @@ export abstract class ActiveOrSuspendedWorkspacesMigrationCommandRunner<
const dataSource =
await this.twentyORMGlobalManager.getDataSourceForWorkspace({
workspaceId,
shouldFailIfMetadataNotFound: false,
});

await this.runOnWorkspace({
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import { MigrationInterface, QueryRunner } from 'typeorm';

export class RemoveRelationMetadata1750673748111 implements MigrationInterface {
name = 'RemoveRelationMetadata1750673748111';

public async up(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`CREATE INDEX "IDX_DATA_SOURCE_WORKSPACE_ID_CREATED_AT" ON "core"."dataSource" ("workspaceId", "createdAt") `,
);
await queryRunner.query(
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

also removing this

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why ?

`ALTER TABLE "core"."relationMetadata" DROP CONSTRAINT IF EXISTS "FK_9dea8f90d04edbbf9c541a95c3b"`,
);
await queryRunner.query(
`ALTER TABLE "core"."relationMetadata" DROP CONSTRAINT IF EXISTS "FK_3deb257254145a3bdde9575e7d6"`,
);
await queryRunner.query(
`ALTER TABLE "core"."relationMetadata" DROP CONSTRAINT IF EXISTS "FK_0f781f589e5a527b8f3d3a4b824"`,
);
await queryRunner.query(
`ALTER TABLE "core"."relationMetadata" DROP CONSTRAINT IF EXISTS "FK_f2a0acd3a548ee446a1a35df44d"`,
);
await queryRunner.query(`DROP TABLE IF EXISTS "core"."relationMetadata"`);
}

public async down(queryRunner: QueryRunner): Promise<void> {
await queryRunner.query(
`DROP INDEX "core"."IDX_DATA_SOURCE_WORKSPACE_ID_CREATED_AT"`,
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { workspaceQueryRunnerGraphqlApiExceptionHandler } from 'src/engine/api/g
import { WorkspaceQueryHookService } from 'src/engine/api/graphql/workspace-query-runner/workspace-query-hook/workspace-query-hook.service';
import { RESOLVER_METHOD_NAMES } from 'src/engine/api/graphql/workspace-resolver-builder/constants/resolver-method-names';
import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { SettingPermissionType } from 'src/engine/metadata-modules/permissions/constants/setting-permission-type.constants';
import {
PermissionsException,
Expand All @@ -37,7 +38,6 @@ import { UserRoleService } from 'src/engine/metadata-modules/user-role/user-role
import { WorkspaceDataSource } from 'src/engine/twenty-orm/datasource/workspace.datasource';
import { WorkspaceRepository } from 'src/engine/twenty-orm/repository/workspace.repository';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';

export type GraphqlQueryResolverExecutionArgs<Input extends ResolverArgs> = {
args: Input;
Expand Down Expand Up @@ -93,7 +93,6 @@ export abstract class GraphqlQueryBaseResolverService<
const workspaceDataSource =
await this.twentyORMGlobalManager.getDataSourceForWorkspace({
workspaceId: workspace.id,
shouldFailIfMetadataNotFound: false,
});

const featureFlagsMap = workspaceDataSource.featureFlagMap;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,26 +3,18 @@ import { Injectable } from '@nestjs/common';
import { makeExecutableSchema } from '@graphql-tools/schema';
import { GraphQLSchema, printSchema } from 'graphql';
import { gql } from 'graphql-tag';
import { isDefined } from 'twenty-shared/utils';

import { ScalarsExplorerService } from 'src/engine/api/graphql/services/scalars-explorer.service';
import { workspaceResolverBuilderMethodNames } from 'src/engine/api/graphql/workspace-resolver-builder/factories/factories';
import { WorkspaceResolverFactory } from 'src/engine/api/graphql/workspace-resolver-builder/workspace-resolver.factory';
import { WorkspaceGraphQLSchemaFactory } from 'src/engine/api/graphql/workspace-schema-builder/workspace-graphql-schema.factory';
import { AuthContext } from 'src/engine/core-modules/auth/types/auth-context.type';
import { FeatureFlagService } from 'src/engine/core-modules/feature-flag/services/feature-flag.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
import { ObjectMetadataMaps } from 'src/engine/metadata-modules/types/object-metadata-maps';
import {
WorkspaceMetadataCacheException,
WorkspaceMetadataCacheExceptionCode,
} from 'src/engine/metadata-modules/workspace-metadata-cache/exceptions/workspace-metadata-cache.exception';
import { WorkspaceMetadataCacheService } from 'src/engine/metadata-modules/workspace-metadata-cache/services/workspace-metadata-cache.service';
import {
WorkspaceMetadataVersionException,
WorkspaceMetadataVersionExceptionCode,
} from 'src/engine/metadata-modules/workspace-metadata-version/exceptions/workspace-metadata-version.exception';
import { WorkspaceCacheStorageService } from 'src/engine/workspace-cache-storage/workspace-cache-storage.service';

@Injectable()
Expand All @@ -34,8 +26,6 @@ export class WorkspaceSchemaFactory {
private readonly workspaceResolverFactory: WorkspaceResolverFactory,
private readonly workspaceCacheStorageService: WorkspaceCacheStorageService,
private readonly workspaceMetadataCacheService: WorkspaceMetadataCacheService,
private readonly featureFlagService: FeatureFlagService,
private readonly twentyConfigService: TwentyConfigService,
) {}

async createGraphQLSchema(authContext: AuthContext): Promise<GraphQLSchema> {
Expand All @@ -52,38 +42,10 @@ export class WorkspaceSchemaFactory {
return new GraphQLSchema({});
}

let currentCacheVersion =
await this.workspaceCacheStorageService.getMetadataVersion(
authContext.workspace.id,
);

let objectMetadataMaps: ObjectMetadataMaps | undefined;

if (currentCacheVersion === undefined) {
const recomputed =
await this.workspaceMetadataCacheService.recomputeMetadataCache({
workspaceId: authContext.workspace.id,
});

objectMetadataMaps = recomputed?.recomputedObjectMetadataMaps;
currentCacheVersion = recomputed?.recomputedMetadataVersion;
} else {
objectMetadataMaps =
await this.workspaceCacheStorageService.getObjectMetadataMaps(
authContext.workspace.id,
currentCacheVersion,
);

if (!isDefined(objectMetadataMaps)) {
const recomputed =
await this.workspaceMetadataCacheService.recomputeMetadataCache({
workspaceId: authContext.workspace.id,
});

objectMetadataMaps = recomputed?.recomputedObjectMetadataMaps;
currentCacheVersion = recomputed?.recomputedMetadataVersion;
}
}
const { objectMetadataMaps, metadataVersion } =
await this.workspaceMetadataCacheService.getFreshObjectMetadataMaps({
workspaceId: authContext.workspace.id,
});

if (!objectMetadataMaps) {
throw new WorkspaceMetadataCacheException(
Expand All @@ -92,13 +54,6 @@ export class WorkspaceSchemaFactory {
);
}

if (!currentCacheVersion) {
throw new WorkspaceMetadataVersionException(
'Metadata cache version not found',
WorkspaceMetadataVersionExceptionCode.METADATA_VERSION_NOT_FOUND,
);
}

const objectMetadataCollection = Object.values(objectMetadataMaps.byId).map(
(objectMetadataItem) => ({
...objectMetadataItem,
Expand All @@ -110,12 +65,12 @@ export class WorkspaceSchemaFactory {
// Get typeDefs from cache
let typeDefs = await this.workspaceCacheStorageService.getGraphQLTypeDefs(
authContext.workspace.id,
currentCacheVersion,
metadataVersion,
);
let usedScalarNames =
await this.workspaceCacheStorageService.getGraphQLUsedScalarNames(
authContext.workspace.id,
currentCacheVersion,
metadataVersion,
);

// If typeDefs are not cached, generate them
Expand All @@ -133,12 +88,12 @@ export class WorkspaceSchemaFactory {

await this.workspaceCacheStorageService.setGraphQLTypeDefs(
authContext.workspace.id,
currentCacheVersion,
metadataVersion,
typeDefs,
);
await this.workspaceCacheStorageService.setGraphQLUsedScalarNames(
authContext.workspace.id,
currentCacheVersion,
metadataVersion,
usedScalarNames,
);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,13 @@ import {
import { JwtWrapperService } from 'src/engine/core-modules/jwt/services/jwt-wrapper.service';
import { TwentyConfigService } from 'src/engine/core-modules/twenty-config/twenty-config.service';
import { UserWorkspace } from 'src/engine/core-modules/user-workspace/user-workspace.entity';
import { userWorkspaceValidator } from 'src/engine/core-modules/user-workspace/user-workspace.validate';
import { User } from 'src/engine/core-modules/user/user.entity';
import { userValidator } from 'src/engine/core-modules/user/user.validate';
import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity';
import { workspaceValidator } from 'src/engine/core-modules/workspace/workspace.validate';
import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager';
import { WorkspaceMemberWorkspaceEntity } from 'src/modules/workspace-member/standard-objects/workspace-member.workspace-entity';
import { userWorkspaceValidator } from 'src/engine/core-modules/user-workspace/user-workspace.validate';

@Injectable()
export class AccessTokenService {
Expand Down Expand Up @@ -78,9 +78,6 @@ export class AccessTokenService {
await this.twentyORMGlobalManager.getRepositoryForWorkspace<WorkspaceMemberWorkspaceEntity>(
workspaceId,
'workspaceMember',
{
shouldFailIfMetadataNotFound: false,
},
);

const workspaceMember = await workspaceMemberRepository.findOne({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -75,15 +75,12 @@ export class FeatureFlagService {

if (keys.includes(FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED)) {
await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache(
{ workspaceId, ignoreLock: true },
{ workspaceId },
);
}

await this.workspaceFeatureFlagsMapCacheService.recomputeFeatureFlagsMapCache(
{
workspaceId,
ignoreLock: true,
},
{ workspaceId },
);
}
}
Expand Down Expand Up @@ -138,15 +135,12 @@ export class FeatureFlagService {
const result = await this.featureFlagRepository.save(featureFlagToSave);

await this.workspaceFeatureFlagsMapCacheService.recomputeFeatureFlagsMapCache(
{
workspaceId,
ignoreLock: true,
},
{ workspaceId },
);

if (featureFlag === FeatureFlagKey.IS_PERMISSIONS_V2_ENABLED) {
await this.workspacePermissionsCacheService.recomputeRolesPermissionsCache(
{ workspaceId, ignoreLock: true },
{ workspaceId },
);
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,20 @@
import {
Column,
CreateDateColumn,
DataSourceOptions,
Entity,
Index,
OneToMany,
PrimaryGeneratedColumn,
UpdateDateColumn,
DataSourceOptions,
OneToMany,
} from 'typeorm';

import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity';

export type DataSourceType = DataSourceOptions['type'];

@Entity('dataSource')
@Index('IDX_DATA_SOURCE_WORKSPACE_ID_CREATED_AT', ['workspaceId', 'createdAt'])
export class DataSourceEntity {
@PrimaryGeneratedColumn('uuid')
id: string;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { PermissionsModule } from 'src/engine/metadata-modules/permissions/permi
import { PermissionsGraphqlApiExceptionFilter } from 'src/engine/metadata-modules/permissions/utils/permissions-graphql-api-exception.filter';
import { RemoteTableRelationsModule } from 'src/engine/metadata-modules/remote-server/remote-table/remote-table-relations/remote-table-relations.module';
import { SearchVectorModule } from 'src/engine/metadata-modules/search-vector/search-vector.module';
import { WorkspaceMetadataCacheModule } from 'src/engine/metadata-modules/workspace-metadata-cache/workspace-metadata-cache.module';
import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module';
import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module';
import { WorkspacePermissionsCacheModule } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.module';
Expand Down Expand Up @@ -59,6 +60,7 @@ import { UpdateObjectPayload } from './dtos/update-object.input';
PermissionsModule,
WorkspacePermissionsCacheModule,
WorkspaceCacheStorageModule,
WorkspaceMetadataCacheModule,
],
services: [
ObjectMetadataService,
Expand Down
Loading
Loading