From 998365457ed61d40d3c65d044f4816aac79be7fa Mon Sep 17 00:00:00 2001 From: Weiko Date: Thu, 13 Nov 2025 18:18:27 +0100 Subject: [PATCH] Improve infer deletion from entities (#15807) ## Context inferDeletionFromEntities only accepts a set of keys for each entities that needs deletion. This could be error-prone if tmr we want to add a new side effect and forget to add the entity when in practice you want to delete all entities that are in the fromToAllFlatEntityMaps (this is the case for applications for example) --- .../application/application-sync.service.ts | 11 +---------- .../services/feature-flag.service.ts | 2 -- .../global-workspace-datasource.service.ts | 6 ++---- ...ted-created-updated-matrix-dispatcher.util.ts | 3 ++- ...-infer-deletion-from-missing-entities.util.ts | 16 ++++++++++++++++ ...kspace-entity-migration-builder-v2.service.ts | 13 +++++++++---- .../workspace-migration-builder-options.type.ts | 4 +++- 7 files changed, 33 insertions(+), 22 deletions(-) create mode 100644 packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/should-infer-deletion-from-missing-entities.util.ts diff --git a/packages/twenty-server/src/engine/core-modules/application/application-sync.service.ts b/packages/twenty-server/src/engine/core-modules/application/application-sync.service.ts index 53336667c0..b3973f329f 100644 --- a/packages/twenty-server/src/engine/core-modules/application/application-sync.service.ts +++ b/packages/twenty-server/src/engine/core-modules/application/application-sync.service.ts @@ -2,7 +2,6 @@ import { Injectable, Logger } from '@nestjs/common'; import { parse } from 'path'; -import { ALL_METADATA_NAME, AllMetadataName } from 'twenty-shared/metadata'; import { isDefined } from 'twenty-shared/utils'; import { ApplicationEntity } from 'src/engine/core-modules/application/application.entity'; @@ -1012,15 +1011,7 @@ export class ApplicationSyncService { workspaceId, buildOptions: { isSystemBuild: true, - inferDeletionFromMissingEntities: { - ...Object.values(ALL_METADATA_NAME).reduce( - (acc, metadataName) => ({ - ...acc, - [metadataName]: true, - }), - {} as Partial>, - ), - }, + inferDeletionFromMissingEntities: true, }, }, ); diff --git a/packages/twenty-server/src/engine/core-modules/feature-flag/services/feature-flag.service.ts b/packages/twenty-server/src/engine/core-modules/feature-flag/services/feature-flag.service.ts index cc7cd669f2..5e2268b7c5 100644 --- a/packages/twenty-server/src/engine/core-modules/feature-flag/services/feature-flag.service.ts +++ b/packages/twenty-server/src/engine/core-modules/feature-flag/services/feature-flag.service.ts @@ -15,7 +15,6 @@ import { import { featureFlagValidator } from 'src/engine/core-modules/feature-flag/validates/feature-flag.validate'; import { publicFeatureFlagValidator } from 'src/engine/core-modules/feature-flag/validates/is-public-feature-flag.validate'; import { WorkspaceFeatureFlagsMapCacheService } from 'src/engine/metadata-modules/workspace-feature-flags-map-cache/workspace-feature-flags-map-cache.service'; -import { WorkspacePermissionsCacheService } from 'src/engine/metadata-modules/workspace-permissions-cache/workspace-permissions-cache.service'; @Injectable() export class FeatureFlagService { @@ -23,7 +22,6 @@ export class FeatureFlagService { @InjectRepository(FeatureFlagEntity) private readonly featureFlagRepository: Repository, private readonly workspaceFeatureFlagsMapCacheService: WorkspaceFeatureFlagsMapCacheService, - private readonly workspacePermissionsCacheService: WorkspacePermissionsCacheService, ) {} public async isFeatureEnabled( diff --git a/packages/twenty-server/src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.service.ts b/packages/twenty-server/src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.service.ts index 99824e4a77..9146597e30 100644 --- a/packages/twenty-server/src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.service.ts +++ b/packages/twenty-server/src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource.service.ts @@ -10,8 +10,6 @@ import { EntitySchemaFactory } from 'src/engine/twenty-orm/factories/entity-sche import { GlobalWorkspaceDataSource } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-datasource'; import { WorkspaceEventEmitter } from 'src/engine/workspace-event-emitter/workspace-event-emitter'; -const TWENTY_MINUTES_IN_MS = 120_000; - @Injectable() export class GlobalWorkspaceDataSourceService implements OnModuleInit, OnApplicationShutdown @@ -38,8 +36,8 @@ export class GlobalWorkspaceDataSourceService } : undefined, extra: { - query_timeout: 10000, - idleTimeoutMillis: TWENTY_MINUTES_IN_MS, + query_timeout: 10000, // 10 seconds, + idleTimeoutMillis: 120_000, // 2 minutes, max: 4, allowExitOnIdle: true, }, diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-entity-deleted-created-updated-matrix-dispatcher.util.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-entity-deleted-created-updated-matrix-dispatcher.util.ts index 84c1a4c3e4..db2fb2a0aa 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-entity-deleted-created-updated-matrix-dispatcher.util.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/flat-entity-deleted-created-updated-matrix-dispatcher.util.ts @@ -11,6 +11,7 @@ import { type MetadataFlatEntityMaps } from 'src/engine/metadata-modules/flat-en import { type MetadataFlatEntity } from 'src/engine/metadata-modules/flat-entity/types/metadata-flat-entity.type'; import { compareTwoFlatEntity } from 'src/engine/metadata-modules/flat-entity/utils/compare-two-flat-entity.util'; import { addFlatEntityToFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration-v2/utils/add-flat-entity-to-flat-entity-maps-through-mutation-or-throw.util'; +import { shouldInferDeletionFromMissingEntities } from 'src/engine/workspace-manager/workspace-migration-v2/utils/should-infer-deletion-from-missing-entities.util'; import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-builder-options.type'; export type DeletedCreatedUpdatedMatrix = { @@ -54,7 +55,7 @@ export const flatEntityDeletedCreatedUpdatedMatrixDispatcher = < const fromMap = new Map(from.map((obj) => [obj.universalIdentifier, obj])); const toMap = new Map(to.map((obj) => [obj.universalIdentifier, obj])); - if (buildOptions.inferDeletionFromMissingEntities?.[metadataName]) { + if (shouldInferDeletionFromMissingEntities({ buildOptions, metadataName })) { for (const [universalIdentifier, fromEntity] of fromMap) { if (toMap.has(universalIdentifier)) { continue; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/should-infer-deletion-from-missing-entities.util.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/should-infer-deletion-from-missing-entities.util.ts new file mode 100644 index 0000000000..0373544cee --- /dev/null +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/utils/should-infer-deletion-from-missing-entities.util.ts @@ -0,0 +1,16 @@ +import { type AllMetadataName } from 'twenty-shared/metadata'; + +import { type WorkspaceMigrationBuilderOptions } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-builder-options.type'; + +export const shouldInferDeletionFromMissingEntities = ({ + buildOptions, + metadataName, +}: { + buildOptions: WorkspaceMigrationBuilderOptions; + metadataName: AllMetadataName; +}): boolean => { + return ( + buildOptions.inferDeletionFromMissingEntities === true || + buildOptions.inferDeletionFromMissingEntities?.[metadataName] === true + ); +}; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-entity-migration-builder-v2.service.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-entity-migration-builder-v2.service.ts index 6173cd80bd..3484b22f97 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-entity-migration-builder-v2.service.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/services/workspace-entity-migration-builder-v2.service.ts @@ -20,6 +20,7 @@ import { deleteFlatEntityFromFlatEntityMapsThroughMutationOrThrow } from 'src/en import { flatEntityDeletedCreatedUpdatedMatrixDispatcher } from 'src/engine/workspace-manager/workspace-migration-v2/utils/flat-entity-deleted-created-updated-matrix-dispatcher.util'; import { getMetadataEmptyWorkspaceMigrationActionRecord } from 'src/engine/workspace-manager/workspace-migration-v2/utils/get-metadata-empty-workspace-migration-action-record.util'; import { replaceFlatEntityInFlatEntityMapsThroughMutationOrThrow } from 'src/engine/workspace-manager/workspace-migration-v2/utils/replace-flat-entity-in-flat-entity-maps-through-mutation-or-throw.util'; +import { shouldInferDeletionFromMissingEntities } from 'src/engine/workspace-manager/workspace-migration-v2/utils/should-infer-deletion-from-missing-entities.util'; import { FailedFlatEntityValidateAndBuild } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/failed-flat-entity-validate-and-build.type'; import { FlatEntityUpdateValidationArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/flat-entity-update-validation-args.type'; import { FlatEntityValidationArgs } from 'src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/flat-entity-validation-args.type'; @@ -161,10 +162,14 @@ export abstract class WorkspaceEntityMigrationBuilderV2Service< deletedFlatEntityMaps, ); - for (const flatEntityToDeleteId in buildOptions - .inferDeletionFromMissingEntities?.[this.metadataName] - ? deletedFlatEntityMaps.byId - : {}) { + const flatEntityToDeleteIds = shouldInferDeletionFromMissingEntities({ + buildOptions, + metadataName: this.metadataName, + }) + ? Object.keys(deletedFlatEntityMaps.byId) + : []; + + for (const flatEntityToDeleteId of flatEntityToDeleteIds) { const flatEntityToDelete = deletedFlatEntityMaps.byId[flatEntityToDeleteId]; diff --git a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-builder-options.type.ts b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-builder-options.type.ts index 2d3325570b..dfee2c42e4 100644 --- a/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-builder-options.type.ts +++ b/packages/twenty-server/src/engine/workspace-manager/workspace-migration-v2/workspace-migration-builder-v2/types/workspace-migration-builder-options.type.ts @@ -1,6 +1,8 @@ import { type AllMetadataName } from 'twenty-shared/metadata'; export type WorkspaceMigrationBuilderOptions = { - inferDeletionFromMissingEntities?: Partial>; + inferDeletionFromMissingEntities?: + | true + | Partial>; isSystemBuild: boolean; };