mirror of
				https://github.com/lingble/twenty.git
				synced 2025-10-31 12:47:58 +00:00 
			
		
		
		
	Optimize sync, reset, seed commands to flush cache and to use less memory (#7034)
In this PR: - removing ugprade-0.24 commands as we are releasing 0.30 - introducing cache:flush command - refactoring upgrade command and sync-metadata command to use the ActiveWorkspacesCommand so they consistently run on all workspaces or selected workspaces Fixes: - clear localStorage on sign out - fix missing workspaceMember in verify resolver - do not throw on datasource already destroyed exception which can happen with race condition when several resolvers are resolving in parallel
This commit is contained in:
		| @@ -254,6 +254,7 @@ export const useAuth = () => { | ||||
|  | ||||
|         await client.clearStore(); | ||||
|         sessionStorage.clear(); | ||||
|         localStorage.clear(); | ||||
|       }, | ||||
|     [client, goToRecoilSnapshot], | ||||
|   ); | ||||
|   | ||||
| @@ -149,6 +149,7 @@ | ||||
|           "nx ts-node-no-deps -- ./scripts/truncate-db.ts", | ||||
|           "nx ts-node-no-deps -- ./scripts/setup-db.ts", | ||||
|           "nx database:migrate", | ||||
|           "nx command-no-deps -- cache:flush", | ||||
|           "nx command-no-deps -- workspace:seed:dev" | ||||
|         ], | ||||
|         "parallel": false | ||||
|   | ||||
| @@ -30,11 +30,11 @@ import { seedPeople } from 'src/database/typeorm-seeds/workspace/people'; | ||||
| import { seedWorkspaceMember } from 'src/database/typeorm-seeds/workspace/workspace-members'; | ||||
| import { rawDataSource } from 'src/database/typeorm/raw/raw.datasource'; | ||||
| import { TypeORMService } from 'src/database/typeorm/typeorm.service'; | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
| import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; | ||||
| import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/cache-storage.service'; | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
| import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; | ||||
| import { FieldMetadataService } from 'src/engine/metadata-modules/field-metadata/field-metadata.service'; | ||||
| import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; | ||||
|   | ||||
| @@ -7,7 +7,6 @@ import { DataSeedDemoWorkspaceCommand } from 'src/database/commands/data-seed-de | ||||
| import { DataSeedDemoWorkspaceModule } from 'src/database/commands/data-seed-demo-workspace/data-seed-demo-workspace.module'; | ||||
| import { DataSeedWorkspaceCommand } from 'src/database/commands/data-seed-dev-workspace.command'; | ||||
| import { ConfirmationQuestion } from 'src/database/commands/questions/confirmation.question'; | ||||
| import { UpgradeTo0_24CommandModule } from 'src/database/commands/upgrade-version/0-24/0-24-upgrade-version.module'; | ||||
| import { UpgradeTo0_30CommandModule } from 'src/database/commands/upgrade-version/0-30/0-30-upgrade-version.module'; | ||||
| import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; | ||||
| import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; | ||||
| @@ -20,9 +19,9 @@ import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/ | ||||
| import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; | ||||
| import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadata/object-metadata.module'; | ||||
| import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module'; | ||||
| import { WorkspaceCacheStorageModule } from 'src/engine/workspace-cache-storage/workspace-cache-storage.module'; | ||||
| import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; | ||||
| import { WorkspaceManagerModule } from 'src/engine/workspace-manager/workspace-manager.module'; | ||||
| import { WorkspaceStatusModule } from 'src/engine/workspace-manager/workspace-status/workspace-manager.module'; | ||||
| import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module'; | ||||
|  | ||||
| @Module({ | ||||
| @@ -41,12 +40,11 @@ import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/worksp | ||||
|     WorkspaceModule, | ||||
|     WorkspaceDataSourceModule, | ||||
|     WorkspaceSyncMetadataModule, | ||||
|     WorkspaceStatusModule, | ||||
|     ObjectMetadataModule, | ||||
|     FieldMetadataModule, | ||||
|     DataSeedDemoWorkspaceModule, | ||||
|     WorkspaceCacheStorageModule, | ||||
|     WorkspaceMetadataVersionModule, | ||||
|     UpgradeTo0_24CommandModule, | ||||
|     UpgradeTo0_30CommandModule, | ||||
|   ], | ||||
|   providers: [ | ||||
|   | ||||
| @@ -1,222 +0,0 @@ | ||||
| import { Logger } from '@nestjs/common'; | ||||
| import { InjectRepository } from '@nestjs/typeorm'; | ||||
|  | ||||
| import chalk from 'chalk'; | ||||
| import { Command, CommandRunner, Option } from 'nest-commander'; | ||||
| import { Any, Repository } from 'typeorm'; | ||||
|  | ||||
| import { | ||||
|   Workspace, | ||||
|   WorkspaceActivationStatus, | ||||
| } from 'src/engine/core-modules/workspace/workspace.entity'; | ||||
| import { WorkspaceMetadataVersionService } from 'src/engine/metadata-modules/workspace-metadata-version/services/workspace-metadata-version.service'; | ||||
| import { TwentyORMGlobalManager } from 'src/engine/twenty-orm/twenty-orm-global.manager'; | ||||
| import { MessageDirection } from 'src/modules/messaging/common/enums/message-direction.enum'; | ||||
| import { MessageChannelMessageAssociationWorkspaceEntity } from 'src/modules/messaging/common/standard-objects/message-channel-message-association.workspace-entity'; | ||||
|  | ||||
| interface SetMessageDirectionCommandOptions { | ||||
|   workspaceId?: string; | ||||
| } | ||||
|  | ||||
| const MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_BATCH_SIZE = 10; | ||||
|  | ||||
| @Command({ | ||||
|   name: 'upgrade-0.24:set-message-direction', | ||||
|   description: 'Set message direction', | ||||
| }) | ||||
| export class SetMessageDirectionCommand extends CommandRunner { | ||||
|   private readonly logger = new Logger(SetMessageDirectionCommand.name); | ||||
|   constructor( | ||||
|     private readonly workspaceMetadataVersionService: WorkspaceMetadataVersionService, | ||||
|     private readonly twentyORMGlobalManager: TwentyORMGlobalManager, | ||||
|     @InjectRepository(Workspace, 'core') | ||||
|     private readonly workspaceRepository: Repository<Workspace>, | ||||
|   ) { | ||||
|     super(); | ||||
|   } | ||||
|  | ||||
|   @Option({ | ||||
|     flags: '-w, --workspace-id [workspace_id]', | ||||
|     description: 'workspace id. Command runs on all workspaces if not provided', | ||||
|     required: false, | ||||
|   }) | ||||
|   parseWorkspaceId(value: string): string { | ||||
|     return value; | ||||
|   } | ||||
|  | ||||
|   async run( | ||||
|     _passedParam: string[], | ||||
|     options: SetMessageDirectionCommandOptions, | ||||
|   ): Promise<void> { | ||||
|     let activeWorkspaceIds: string[] = []; | ||||
|  | ||||
|     if (options.workspaceId) { | ||||
|       activeWorkspaceIds = [options.workspaceId]; | ||||
|     } else { | ||||
|       const activeWorkspaces = await this.workspaceRepository.find({ | ||||
|         where: { | ||||
|           activationStatus: WorkspaceActivationStatus.ACTIVE, | ||||
|           ...(options.workspaceId && { id: options.workspaceId }), | ||||
|         }, | ||||
|       }); | ||||
|  | ||||
|       activeWorkspaceIds = activeWorkspaces.map((workspace) => workspace.id); | ||||
|     } | ||||
|  | ||||
|     if (!activeWorkspaceIds.length) { | ||||
|       this.logger.log(chalk.yellow('No workspace found')); | ||||
|  | ||||
|       return; | ||||
|     } else { | ||||
|       this.logger.log( | ||||
|         chalk.green( | ||||
|           `Running command on ${activeWorkspaceIds.length} workspaces`, | ||||
|         ), | ||||
|       ); | ||||
|     } | ||||
|  | ||||
|     for (const workspaceId of activeWorkspaceIds) { | ||||
|       try { | ||||
|         const messageChannelMessageAssociationRepository = | ||||
|           await this.twentyORMGlobalManager.getRepositoryForWorkspace<MessageChannelMessageAssociationWorkspaceEntity>( | ||||
|             workspaceId, | ||||
|             'messageChannelMessageAssociation', | ||||
|           ); | ||||
|  | ||||
|         const workspaceDataSource = | ||||
|           await this.twentyORMGlobalManager.getDataSourceForWorkspace( | ||||
|             workspaceId, | ||||
|           ); | ||||
|  | ||||
|         await workspaceDataSource.transaction(async (transactionManager) => { | ||||
|           try { | ||||
|             const messageChannelMessageAssociationCount = | ||||
|               await messageChannelMessageAssociationRepository.count( | ||||
|                 {}, | ||||
|                 transactionManager, | ||||
|               ); | ||||
|  | ||||
|             for ( | ||||
|               let i = 0; | ||||
|               i < messageChannelMessageAssociationCount; | ||||
|               i += MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_BATCH_SIZE | ||||
|             ) { | ||||
|               const messageChannelMessageAssociationsPage = | ||||
|                 await messageChannelMessageAssociationRepository.find( | ||||
|                   { | ||||
|                     where: { | ||||
|                       message: { | ||||
|                         messageParticipants: { | ||||
|                           role: 'from', | ||||
|                         }, | ||||
|                       }, | ||||
|                     }, | ||||
|                     relations: { | ||||
|                       message: { | ||||
|                         messageParticipants: true, | ||||
|                       }, | ||||
|                       messageChannel: { | ||||
|                         connectedAccount: true, | ||||
|                       }, | ||||
|                     }, | ||||
|                     take: MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_BATCH_SIZE, | ||||
|                     skip: i, | ||||
|                   }, | ||||
|                   transactionManager, | ||||
|                 ); | ||||
|  | ||||
|               const { incoming, outgoing } = | ||||
|                 messageChannelMessageAssociationsPage.reduce( | ||||
|                   ( | ||||
|                     acc: { | ||||
|                       incoming: string[]; | ||||
|                       outgoing: string[]; | ||||
|                     }, | ||||
|                     messageChannelMessageAssociation, | ||||
|                   ) => { | ||||
|                     const connectedAccountHandle = | ||||
|                       messageChannelMessageAssociation?.messageChannel | ||||
|                         ?.connectedAccount?.handle; | ||||
|                     const connectedAccountHandleAliases = | ||||
|                       messageChannelMessageAssociation?.messageChannel | ||||
|                         ?.connectedAccount?.handleAliases; | ||||
|                     const fromHandle = | ||||
|                       messageChannelMessageAssociation?.message | ||||
|                         ?.messageParticipants?.[0]?.handle ?? ''; | ||||
|  | ||||
|                     if ( | ||||
|                       connectedAccountHandle === fromHandle || | ||||
|                       connectedAccountHandleAliases?.includes(fromHandle) | ||||
|                     ) { | ||||
|                       acc.outgoing.push(messageChannelMessageAssociation.id); | ||||
|                     } else { | ||||
|                       acc.incoming.push(messageChannelMessageAssociation.id); | ||||
|                     } | ||||
|  | ||||
|                     return acc; | ||||
|                   }, | ||||
|                   { incoming: [], outgoing: [] }, | ||||
|                 ); | ||||
|  | ||||
|               await messageChannelMessageAssociationRepository.update( | ||||
|                 { | ||||
|                   id: Any(incoming), | ||||
|                 }, | ||||
|                 { | ||||
|                   direction: MessageDirection.INCOMING, | ||||
|                 }, | ||||
|                 transactionManager, | ||||
|               ); | ||||
|  | ||||
|               await messageChannelMessageAssociationRepository.update( | ||||
|                 { | ||||
|                   id: Any(outgoing), | ||||
|                 }, | ||||
|                 { | ||||
|                   direction: MessageDirection.OUTGOING, | ||||
|                 }, | ||||
|                 transactionManager, | ||||
|               ); | ||||
|  | ||||
|               const numberOfProcessedAssociations = | ||||
|                 i + MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_BATCH_SIZE; | ||||
|  | ||||
|               if ( | ||||
|                 numberOfProcessedAssociations % | ||||
|                   (MESSAGE_CHANNEL_MESSAGE_ASSOCIATION_BATCH_SIZE * 10) === | ||||
|                   0 || | ||||
|                 numberOfProcessedAssociations >= | ||||
|                   messageChannelMessageAssociationCount | ||||
|               ) { | ||||
|                 this.logger.log( | ||||
|                   chalk.green( | ||||
|                     `Processed ${Math.min(numberOfProcessedAssociations, messageChannelMessageAssociationCount)} of ${messageChannelMessageAssociationCount} message channel message associations`, | ||||
|                   ), | ||||
|                 ); | ||||
|               } | ||||
|             } | ||||
|           } catch (error) { | ||||
|             this.logger.log( | ||||
|               chalk.red(`Running command on workspace ${workspaceId} failed`), | ||||
|             ); | ||||
|             throw error; | ||||
|           } | ||||
|         }); | ||||
|  | ||||
|         await this.workspaceMetadataVersionService.incrementMetadataVersion( | ||||
|           workspaceId, | ||||
|         ); | ||||
|  | ||||
|         this.logger.log( | ||||
|           chalk.green(`Running command on workspace ${workspaceId} done`), | ||||
|         ); | ||||
|       } catch (error) { | ||||
|         this.logger.error( | ||||
|           `Migration failed for workspace ${workspaceId}: ${error.message}`, | ||||
|         ); | ||||
|       } | ||||
|     } | ||||
|  | ||||
|     this.logger.log(chalk.green(`Command completed!`)); | ||||
|   } | ||||
| } | ||||
| @@ -1,42 +0,0 @@ | ||||
| import { Command, CommandRunner, Option } from 'nest-commander'; | ||||
|  | ||||
| import { SetMessageDirectionCommand } from 'src/database/commands/upgrade-version/0-24/0-24-set-message-direction.command'; | ||||
| import { SyncWorkspaceMetadataCommand } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/sync-workspace-metadata.command'; | ||||
|  | ||||
| interface UpdateTo0_24CommandOptions { | ||||
|   workspaceId?: string; | ||||
| } | ||||
|  | ||||
| @Command({ | ||||
|   name: 'upgrade-0.24', | ||||
|   description: 'Upgrade to 0.24', | ||||
| }) | ||||
| export class UpgradeTo0_24Command extends CommandRunner { | ||||
|   constructor( | ||||
|     private readonly syncWorkspaceMetadataCommand: SyncWorkspaceMetadataCommand, | ||||
|     private readonly setMessagesDirectionCommand: SetMessageDirectionCommand, | ||||
|   ) { | ||||
|     super(); | ||||
|   } | ||||
|  | ||||
|   @Option({ | ||||
|     flags: '-w, --workspace-id [workspace_id]', | ||||
|     description: | ||||
|       'workspace id. Command runs on all active workspaces if not provided', | ||||
|     required: false, | ||||
|   }) | ||||
|   parseWorkspaceId(value: string): string { | ||||
|     return value; | ||||
|   } | ||||
|  | ||||
|   async run( | ||||
|     passedParam: string[], | ||||
|     options: UpdateTo0_24CommandOptions, | ||||
|   ): Promise<void> { | ||||
|     await this.syncWorkspaceMetadataCommand.run(passedParam, { | ||||
|       ...options, | ||||
|       force: true, | ||||
|     }); | ||||
|     await this.setMessagesDirectionCommand.run(passedParam, options); | ||||
|   } | ||||
| } | ||||
| @@ -1,43 +0,0 @@ | ||||
| import { Module } from '@nestjs/common'; | ||||
| import { TypeOrmModule } from '@nestjs/typeorm'; | ||||
|  | ||||
| import { SetMessageDirectionCommand } from 'src/database/commands/upgrade-version/0-24/0-24-set-message-direction.command'; | ||||
| import { UpgradeTo0_24Command } from 'src/database/commands/upgrade-version/0-24/0-24-upgrade-version.command'; | ||||
| import { SetCustomObjectIsSoftDeletableCommand } from 'src/database/commands/upgrade-version/0-30/0-30-set-custom-object-is-soft-deletable.command'; | ||||
| import { TypeORMModule } from 'src/database/typeorm/typeorm.module'; | ||||
| import { KeyValuePair } from 'src/engine/core-modules/key-value-pair/key-value-pair.entity'; | ||||
| import { OnboardingModule } from 'src/engine/core-modules/onboarding/onboarding.module'; | ||||
| import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; | ||||
| import { FileStorageModule } from 'src/engine/core-modules/file-storage/file-storage.module'; | ||||
| import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; | ||||
| import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity'; | ||||
| import { FieldMetadataModule } from 'src/engine/metadata-modules/field-metadata/field-metadata.module'; | ||||
| import { ObjectMetadataEntity } from 'src/engine/metadata-modules/object-metadata/object-metadata.entity'; | ||||
| import { WorkspaceMetadataVersionModule } from 'src/engine/metadata-modules/workspace-metadata-version/workspace-metadata-version.module'; | ||||
| import { WorkspaceStatusModule } from 'src/engine/workspace-manager/workspace-status/workspace-manager.module'; | ||||
| import { WorkspaceSyncMetadataCommandsModule } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/workspace-sync-metadata-commands.module'; | ||||
|  | ||||
| @Module({ | ||||
|   imports: [ | ||||
|     TypeOrmModule.forFeature([Workspace, KeyValuePair], 'core'), | ||||
|     WorkspaceSyncMetadataCommandsModule, | ||||
|     FileStorageModule, | ||||
|     OnboardingModule, | ||||
|     TypeORMModule, | ||||
|     DataSourceModule, | ||||
|     WorkspaceMetadataVersionModule, | ||||
|     FieldMetadataModule, | ||||
|     WorkspaceStatusModule, | ||||
|     TypeOrmModule.forFeature( | ||||
|       [FieldMetadataEntity, ObjectMetadataEntity], | ||||
|       'metadata', | ||||
|     ), | ||||
|     TypeORMModule, | ||||
|   ], | ||||
|   providers: [ | ||||
|     UpgradeTo0_24Command, | ||||
|     SetMessageDirectionCommand, | ||||
|     SetCustomObjectIsSoftDeletableCommand, | ||||
|   ], | ||||
| }) | ||||
| export class UpgradeTo0_24CommandModule {} | ||||
| @@ -1,7 +1,12 @@ | ||||
| import { Command, CommandRunner, Option } from 'nest-commander'; | ||||
| import { InjectRepository } from '@nestjs/typeorm'; | ||||
|  | ||||
| import { Command } from 'nest-commander'; | ||||
| import { Repository } from 'typeorm'; | ||||
|  | ||||
| import { ActiveWorkspacesCommandRunner } from 'src/database/commands/active-workspaces.command'; | ||||
| import { MigrateEmailFieldsToEmailsCommand } from 'src/database/commands/upgrade-version/0-30/0-30-migrate-email-fields-to-emails.command'; | ||||
| import { SetCustomObjectIsSoftDeletableCommand } from 'src/database/commands/upgrade-version/0-30/0-30-set-custom-object-is-soft-deletable.command'; | ||||
| import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; | ||||
| import { SyncWorkspaceMetadataCommand } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/sync-workspace-metadata.command'; | ||||
|  | ||||
| interface UpdateTo0_30CommandOptions { | ||||
| @@ -12,34 +17,39 @@ interface UpdateTo0_30CommandOptions { | ||||
|   name: 'upgrade-0.30', | ||||
|   description: 'Upgrade to 0.30', | ||||
| }) | ||||
| export class UpgradeTo0_30Command extends CommandRunner { | ||||
| export class UpgradeTo0_30Command extends ActiveWorkspacesCommandRunner { | ||||
|   constructor( | ||||
|     @InjectRepository(Workspace, 'core') | ||||
|     protected readonly workspaceRepository: Repository<Workspace>, | ||||
|     private readonly syncWorkspaceMetadataCommand: SyncWorkspaceMetadataCommand, | ||||
|     private readonly migrateEmailFieldsToEmails: MigrateEmailFieldsToEmailsCommand, | ||||
|     private readonly setCustomObjectIsSoftDeletableCommand: SetCustomObjectIsSoftDeletableCommand, | ||||
|   ) { | ||||
|     super(); | ||||
|     super(workspaceRepository); | ||||
|   } | ||||
|  | ||||
|   @Option({ | ||||
|     flags: '-w, --workspace-id [workspace_id]', | ||||
|     description: | ||||
|       'workspace id. Command runs on all active workspaces if not provided', | ||||
|     required: false, | ||||
|   }) | ||||
|   parseWorkspaceId(value: string): string { | ||||
|     return value; | ||||
|   } | ||||
|  | ||||
|   async run( | ||||
|   async executeActiveWorkspacesCommand( | ||||
|     passedParam: string[], | ||||
|     options: UpdateTo0_30CommandOptions, | ||||
|     workspaceIds: string[], | ||||
|   ): Promise<void> { | ||||
|     await this.syncWorkspaceMetadataCommand.run(passedParam, { | ||||
|     await this.syncWorkspaceMetadataCommand.executeActiveWorkspacesCommand( | ||||
|       passedParam, | ||||
|       { | ||||
|         ...options, | ||||
|         force: true, | ||||
|     }); | ||||
|     await this.setCustomObjectIsSoftDeletableCommand.run(passedParam, options); | ||||
|     await this.migrateEmailFieldsToEmails.run(passedParam, options); | ||||
|       }, | ||||
|       workspaceIds, | ||||
|     ); | ||||
|     await this.setCustomObjectIsSoftDeletableCommand.executeActiveWorkspacesCommand( | ||||
|       passedParam, | ||||
|       options, | ||||
|       workspaceIds, | ||||
|     ); | ||||
|     await this.migrateEmailFieldsToEmails.executeActiveWorkspacesCommand( | ||||
|       passedParam, | ||||
|       options, | ||||
|       workspaceIds, | ||||
|     ); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -4,7 +4,7 @@ import GraphQLJSON from 'graphql-type-json'; | ||||
| import { useCachedMetadata } from 'src/engine/api/graphql/graphql-config/hooks/use-cached-metadata'; | ||||
| import { useThrottler } from 'src/engine/api/graphql/graphql-config/hooks/use-throttler'; | ||||
| import { MetadataGraphQLApiModule } from 'src/engine/api/graphql/metadata-graphql-api.module'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/cache-storage.service'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; | ||||
| import { ExceptionHandlerService } from 'src/engine/core-modules/exception-handler/exception-handler.service'; | ||||
| import { useGraphQLErrorHandlerHook } from 'src/engine/core-modules/graphql/hooks/use-graphql-error-handler.hook'; | ||||
|   | ||||
| @@ -34,7 +34,6 @@ import { WorkspaceInviteHashValid } from 'src/engine/core-modules/auth/dto/works | ||||
| import { SignInUpService } from 'src/engine/core-modules/auth/services/sign-in-up.service'; | ||||
| import { EmailService } from 'src/engine/core-modules/email/email.service'; | ||||
| import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; | ||||
| import { WorkspaceMember } from 'src/engine/core-modules/user/dtos/workspace-member.dto'; | ||||
| import { UserService } from 'src/engine/core-modules/user/services/user.service'; | ||||
| import { User } from 'src/engine/core-modules/user/user.entity'; | ||||
| import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; | ||||
| @@ -150,14 +149,6 @@ export class AuthService { | ||||
|  | ||||
|     // passwordHash is hidden for security reasons | ||||
|     user.passwordHash = ''; | ||||
|     const workspaceMember = await this.userService.loadWorkspaceMember( | ||||
|       user, | ||||
|       user.defaultWorkspace, | ||||
|     ); | ||||
|  | ||||
|     if (workspaceMember) { | ||||
|       user.workspaceMember = workspaceMember as WorkspaceMember; | ||||
|     } | ||||
|  | ||||
|     const accessToken = await this.tokenService.generateAccessToken(user.id); | ||||
|     const refreshToken = await this.tokenService.generateRefreshToken(user.id); | ||||
|   | ||||
| @@ -1,11 +1,12 @@ | ||||
| import { Module, Global, Inject, OnModuleDestroy } from '@nestjs/common'; | ||||
| import { CacheModule, CACHE_MANAGER, Cache } from '@nestjs/cache-manager'; | ||||
| import { CACHE_MANAGER, Cache, CacheModule } from '@nestjs/cache-manager'; | ||||
| import { Global, Inject, Module, OnModuleDestroy } from '@nestjs/common'; | ||||
| import { ConfigModule } from '@nestjs/config'; | ||||
|  | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/cache-storage.service'; | ||||
| import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; | ||||
| import { cacheStorageModuleFactory } from 'src/engine/core-modules/cache-storage/cache-storage.module-factory'; | ||||
| import { FlushCacheCommand } from 'src/engine/core-modules/cache-storage/commands/flush-cache.command'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
| import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; | ||||
|  | ||||
| @Global() | ||||
| @Module({ | ||||
| @@ -25,8 +26,9 @@ import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/typ | ||||
|       }, | ||||
|       inject: [CACHE_MANAGER], | ||||
|     })), | ||||
|     FlushCacheCommand, | ||||
|   ], | ||||
|   exports: [...Object.values(CacheStorageNamespace)], | ||||
|   exports: [...Object.values(CacheStorageNamespace), FlushCacheCommand], | ||||
| }) | ||||
| export class CacheStorageModule implements OnModuleDestroy { | ||||
|   constructor(@Inject(CACHE_MANAGER) private cacheManager: Cache) {} | ||||
|   | ||||
| @@ -0,0 +1,29 @@ | ||||
| import { Logger } from '@nestjs/common'; | ||||
|  | ||||
| import { Command, CommandRunner } from 'nest-commander'; | ||||
|  | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
|  | ||||
| // TODO: implement dry-run | ||||
| @Command({ | ||||
|   name: 'cache:flush', | ||||
|   description: 'Completely flush cache', | ||||
| }) | ||||
| export class FlushCacheCommand extends CommandRunner { | ||||
|   private readonly logger = new Logger(FlushCacheCommand.name); | ||||
|  | ||||
|   constructor( | ||||
|     @InjectCacheStorage(CacheStorageNamespace.EngineWorkspace) | ||||
|     private readonly cacheStorage: CacheStorageService, | ||||
|   ) { | ||||
|     super(); | ||||
|   } | ||||
|  | ||||
|   async run(): Promise<void> { | ||||
|     this.logger.log('Flushing cache...'); | ||||
|     await this.cacheStorage.flush(); | ||||
|     this.logger.log('Cache flushed'); | ||||
|   } | ||||
| } | ||||
| @@ -1,12 +1,12 @@ | ||||
| import { Injectable } from '@nestjs/common'; | ||||
|  | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
| import { | ||||
|   ThrottlerException, | ||||
|   ThrottlerExceptionCode, | ||||
| } from 'src/engine/core-modules/throttler/throttler.exception'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/cache-storage.service'; | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
|  | ||||
| @Injectable() | ||||
| export class ThrottlerService { | ||||
|   | ||||
| @@ -103,7 +103,7 @@ export class UserResolver { | ||||
|   ): Promise<WorkspaceMember | null> { | ||||
|     const workspaceMember = await this.userService.loadWorkspaceMember( | ||||
|       user, | ||||
|       workspace, | ||||
|       workspace ?? user.defaultWorkspace, | ||||
|     ); | ||||
|  | ||||
|     if (workspaceMember && workspaceMember.avatarUrl) { | ||||
|   | ||||
| @@ -21,7 +21,6 @@ import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadat | ||||
| 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 { WorkspaceMigrationRunnerModule } from 'src/engine/workspace-manager/workspace-migration-runner/workspace-migration-runner.module'; | ||||
| import { WorkspaceStatusModule } from 'src/engine/workspace-manager/workspace-status/workspace-manager.module'; | ||||
|  | ||||
| import { FieldMetadataEntity } from './field-metadata.entity'; | ||||
| import { FieldMetadataService } from './field-metadata.service'; | ||||
| @@ -38,7 +37,6 @@ import { UpdateFieldInput } from './dtos/update-field.input'; | ||||
|           'metadata', | ||||
|         ), | ||||
|         WorkspaceMigrationModule, | ||||
|         WorkspaceStatusModule, | ||||
|         WorkspaceMigrationRunnerModule, | ||||
|         WorkspaceMetadataVersionModule, | ||||
|         ObjectMetadataModule, | ||||
|   | ||||
| @@ -48,7 +48,5 @@ export class WorkspaceMetadataVersionService { | ||||
|     await this.workspaceMetadataCacheService.recomputeMetadataCache( | ||||
|       workspaceId, | ||||
|     ); | ||||
|  | ||||
|     await this.twentyORMGlobalManager.loadDataSourceForWorkspace(workspaceId); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -146,7 +146,18 @@ export class WorkspaceDatasourceFactory { | ||||
|  | ||||
|         return workspaceDataSource; | ||||
|       }, | ||||
|       (dataSource) => dataSource.destroy(), | ||||
|       async (dataSource) => { | ||||
|         try { | ||||
|           await dataSource.destroy(); | ||||
|         } catch (error) { | ||||
|           // Ignore error if pool has already been destroyed which is a common race condition case | ||||
|           if (error.message === 'Called end on pool more than once') { | ||||
|             return; | ||||
|           } | ||||
|  | ||||
|           throw error; | ||||
|         } | ||||
|       }, | ||||
|     ); | ||||
|  | ||||
|     if (!workspaceDataSource) { | ||||
|   | ||||
| @@ -2,8 +2,8 @@ import { Injectable } from '@nestjs/common'; | ||||
|  | ||||
| import { EntitySchemaOptions } from 'typeorm'; | ||||
|  | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/cache-storage.service'; | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
| import { ObjectMetadataMap } from 'src/engine/metadata-modules/utils/generate-object-metadata-map.util'; | ||||
|  | ||||
|   | ||||
| @@ -5,7 +5,6 @@ import { ObjectMetadataModule } from 'src/engine/metadata-modules/object-metadat | ||||
| import { WorkspaceMigrationModule } from 'src/engine/metadata-modules/workspace-migration/workspace-migration.module'; | ||||
| import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; | ||||
| import { WorkspaceHealthModule } from 'src/engine/workspace-manager/workspace-health/workspace-health.module'; | ||||
| import { WorkspaceStatusModule } from 'src/engine/workspace-manager/workspace-status/workspace-manager.module'; | ||||
| import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module'; | ||||
|  | ||||
| import { WorkspaceManagerService } from './workspace-manager.service'; | ||||
| @@ -18,7 +17,6 @@ import { WorkspaceManagerService } from './workspace-manager.service'; | ||||
|     DataSourceModule, | ||||
|     WorkspaceSyncMetadataModule, | ||||
|     WorkspaceHealthModule, | ||||
|     WorkspaceStatusModule, | ||||
|   ], | ||||
|   exports: [WorkspaceManagerService], | ||||
|   providers: [WorkspaceManagerService], | ||||
|   | ||||
| @@ -1,72 +0,0 @@ | ||||
| import { Injectable } from '@nestjs/common'; | ||||
| import { InjectRepository } from '@nestjs/typeorm'; | ||||
|  | ||||
| import { Any, Repository } from 'typeorm'; | ||||
|  | ||||
| import { | ||||
|   BillingSubscription, | ||||
|   SubscriptionStatus, | ||||
| } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; | ||||
| import { FeatureFlagKey } from 'src/engine/core-modules/feature-flag/enums/feature-flag-key.enum'; | ||||
| import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; | ||||
| import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; | ||||
| import { EnvironmentService } from 'src/engine/core-modules/environment/environment.service'; | ||||
|  | ||||
| @Injectable() | ||||
| export class WorkspaceStatusService { | ||||
|   constructor( | ||||
|     private readonly environmentService: EnvironmentService, | ||||
|     @InjectRepository(Workspace, 'core') | ||||
|     private readonly workspaceRepository: Repository<Workspace>, | ||||
|     @InjectRepository(BillingSubscription, 'core') | ||||
|     private readonly billingSubscriptionRepository: Repository<BillingSubscription>, | ||||
|     @InjectRepository(FeatureFlagEntity, 'core') | ||||
|     private readonly featureFlagRepository: Repository<FeatureFlagEntity>, | ||||
|   ) {} | ||||
|  | ||||
|   async getActiveWorkspaceIds(): Promise<string[]> { | ||||
|     const workspaces = await this.workspaceRepository.find(); | ||||
|     const workspaceIds = workspaces.map((workspace) => workspace.id); | ||||
|  | ||||
|     if (!this.environmentService.get('IS_BILLING_ENABLED')) { | ||||
|       return workspaceIds; | ||||
|     } | ||||
|  | ||||
|     const billingSubscriptionForWorkspaces = | ||||
|       await this.billingSubscriptionRepository.find({ | ||||
|         where: { | ||||
|           workspaceId: Any(workspaceIds), | ||||
|           status: Any([ | ||||
|             SubscriptionStatus.PastDue, | ||||
|             SubscriptionStatus.Active, | ||||
|             SubscriptionStatus.Trialing, | ||||
|           ]), | ||||
|         }, | ||||
|       }); | ||||
|  | ||||
|     const workspaceIdsWithActiveSubscription = | ||||
|       billingSubscriptionForWorkspaces.map( | ||||
|         (billingSubscription) => billingSubscription.workspaceId, | ||||
|       ); | ||||
|  | ||||
|     const freeAccessEnabledFeatureFlagForWorkspace = | ||||
|       await this.featureFlagRepository.find({ | ||||
|         where: { | ||||
|           workspaceId: Any(workspaceIds), | ||||
|           key: FeatureFlagKey.IsFreeAccessEnabled, | ||||
|           value: true, | ||||
|         }, | ||||
|       }); | ||||
|  | ||||
|     const workspaceIdsWithFreeAccessEnabled = | ||||
|       freeAccessEnabledFeatureFlagForWorkspace.map( | ||||
|         (featureFlag) => featureFlag.workspaceId, | ||||
|       ); | ||||
|  | ||||
|     return workspaceIds.filter( | ||||
|       (workspaceId) => | ||||
|         workspaceIdsWithActiveSubscription.includes(workspaceId) || | ||||
|         workspaceIdsWithFreeAccessEnabled.includes(workspaceId), | ||||
|     ); | ||||
|   } | ||||
| } | ||||
| @@ -1,21 +0,0 @@ | ||||
| import { Module } from '@nestjs/common'; | ||||
| import { TypeOrmModule } from '@nestjs/typeorm'; | ||||
|  | ||||
| import { BillingSubscription } from 'src/engine/core-modules/billing/entities/billing-subscription.entity'; | ||||
| import { FeatureFlagEntity } from 'src/engine/core-modules/feature-flag/feature-flag.entity'; | ||||
| import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; | ||||
| import { EnvironmentModule } from 'src/engine/core-modules/environment/environment.module'; | ||||
| import { WorkspaceStatusService } from 'src/engine/workspace-manager/workspace-status/services/workspace-status.service'; | ||||
|  | ||||
| @Module({ | ||||
|   imports: [ | ||||
|     EnvironmentModule, | ||||
|     TypeOrmModule.forFeature( | ||||
|       [Workspace, BillingSubscription, FeatureFlagEntity], | ||||
|       'core', | ||||
|     ), | ||||
|   ], | ||||
|   exports: [WorkspaceStatusService], | ||||
|   providers: [WorkspaceStatusService], | ||||
| }) | ||||
| export class WorkspaceStatusModule {} | ||||
| @@ -1,11 +1,12 @@ | ||||
| import { Logger } from '@nestjs/common'; | ||||
| import { InjectRepository } from '@nestjs/typeorm'; | ||||
|  | ||||
| import isEmpty from 'lodash.isempty'; | ||||
| import { Command, CommandRunner, Option } from 'nest-commander'; | ||||
| import { Command, Option } from 'nest-commander'; | ||||
| import { Repository } from 'typeorm'; | ||||
|  | ||||
| import { ActiveWorkspacesCommandRunner } from 'src/database/commands/active-workspaces.command'; | ||||
| import { Workspace } from 'src/engine/core-modules/workspace/workspace.entity'; | ||||
| import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service'; | ||||
| import { WorkspaceHealthService } from 'src/engine/workspace-manager/workspace-health/workspace-health.service'; | ||||
| import { WorkspaceStatusService } from 'src/engine/workspace-manager/workspace-status/services/workspace-status.service'; | ||||
| import { WorkspaceSyncMetadataService } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.service'; | ||||
|  | ||||
| import { SyncWorkspaceLoggerService } from './services/sync-workspace-logger.service'; | ||||
| @@ -21,35 +22,24 @@ interface RunWorkspaceMigrationsOptions { | ||||
|   name: 'workspace:sync-metadata', | ||||
|   description: 'Sync metadata', | ||||
| }) | ||||
| export class SyncWorkspaceMetadataCommand extends CommandRunner { | ||||
|   private readonly logger = new Logger(SyncWorkspaceMetadataCommand.name); | ||||
|  | ||||
| export class SyncWorkspaceMetadataCommand extends ActiveWorkspacesCommandRunner { | ||||
|   constructor( | ||||
|     @InjectRepository(Workspace, 'core') | ||||
|     protected readonly workspaceRepository: Repository<Workspace>, | ||||
|     private readonly workspaceSyncMetadataService: WorkspaceSyncMetadataService, | ||||
|     private readonly workspaceHealthService: WorkspaceHealthService, | ||||
|     private readonly dataSourceService: DataSourceService, | ||||
|     private readonly syncWorkspaceLoggerService: SyncWorkspaceLoggerService, | ||||
|     private readonly workspaceStatusService: WorkspaceStatusService, | ||||
|   ) { | ||||
|     super(); | ||||
|     super(workspaceRepository); | ||||
|   } | ||||
|  | ||||
|   async run( | ||||
|   async executeActiveWorkspacesCommand( | ||||
|     _passedParam: string[], | ||||
|     options: RunWorkspaceMigrationsOptions, | ||||
|     workspaceIds: string[], | ||||
|   ): Promise<void> { | ||||
|     // TODO: re-implement load index from workspaceService, this is breaking the logger | ||||
|     let workspaceIds = options.workspaceId ? [options.workspaceId] : []; | ||||
|  | ||||
|     if (isEmpty(workspaceIds)) { | ||||
|       const activeWorkspaceIds = | ||||
|         await this.workspaceStatusService.getActiveWorkspaceIds(); | ||||
|  | ||||
|       workspaceIds = activeWorkspaceIds; | ||||
|       this.logger.log( | ||||
|         `Attempting to sync ${activeWorkspaceIds.length} workspaces.`, | ||||
|       ); | ||||
|     } | ||||
|     this.logger.log(`Attempting to sync ${workspaceIds.length} workspaces.`); | ||||
|  | ||||
|     let count = 1; | ||||
|  | ||||
| @@ -138,15 +128,6 @@ export class SyncWorkspaceMetadataCommand extends CommandRunner { | ||||
|     ); | ||||
|   } | ||||
|  | ||||
|   @Option({ | ||||
|     flags: '-w, --workspace-id [workspace_id]', | ||||
|     description: 'workspace id', | ||||
|     required: false, | ||||
|   }) | ||||
|   parseWorkspaceId(value: string): string { | ||||
|     return value; | ||||
|   } | ||||
|  | ||||
|   @Option({ | ||||
|     flags: '-d, --dry-run', | ||||
|     description: 'Dry run without applying changes', | ||||
|   | ||||
| @@ -6,7 +6,6 @@ import { WorkspaceModule } from 'src/engine/core-modules/workspace/workspace.mod | ||||
| import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module'; | ||||
| import { WorkspaceDataSourceModule } from 'src/engine/workspace-datasource/workspace-datasource.module'; | ||||
| import { WorkspaceHealthModule } from 'src/engine/workspace-manager/workspace-health/workspace-health.module'; | ||||
| import { WorkspaceStatusModule } from 'src/engine/workspace-manager/workspace-status/workspace-manager.module'; | ||||
| import { ConvertRecordPositionsToIntegers } from 'src/engine/workspace-manager/workspace-sync-metadata/commands/convert-record-positions-to-integers.command'; | ||||
| import { WorkspaceSyncMetadataModule } from 'src/engine/workspace-manager/workspace-sync-metadata/workspace-sync-metadata.module'; | ||||
|  | ||||
| @@ -22,7 +21,6 @@ import { SyncWorkspaceLoggerService } from './services/sync-workspace-logger.ser | ||||
|     DataSourceModule, | ||||
|     WorkspaceDataSourceModule, | ||||
|     TypeOrmModule.forFeature([Workspace], 'core'), | ||||
|     WorkspaceStatusModule, | ||||
|   ], | ||||
|   providers: [ | ||||
|     SyncWorkspaceMetadataCommand, | ||||
|   | ||||
| @@ -2,8 +2,8 @@ import { Injectable } from '@nestjs/common'; | ||||
|  | ||||
| import { Any } from 'typeorm'; | ||||
|  | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/cache-storage.service'; | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
| import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; | ||||
| import { | ||||
|   | ||||
| @@ -2,8 +2,8 @@ import { Injectable } from '@nestjs/common'; | ||||
|  | ||||
| import { Any } from 'typeorm'; | ||||
|  | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/cache-storage.service'; | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
| import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; | ||||
| import { AccountsToReconnectService } from 'src/modules/connected-account/services/accounts-to-reconnect.service'; | ||||
|   | ||||
| @@ -1,5 +1,5 @@ | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/cache-storage.service'; | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
| import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator'; | ||||
| import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator'; | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { Logger } from '@nestjs/common'; | ||||
|  | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/cache-storage.service'; | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
| import { Process } from 'src/engine/core-modules/message-queue/decorators/process.decorator'; | ||||
| import { Processor } from 'src/engine/core-modules/message-queue/decorators/processor.decorator'; | ||||
|   | ||||
| @@ -2,8 +2,8 @@ import { Injectable } from '@nestjs/common'; | ||||
|  | ||||
| import { Any } from 'typeorm'; | ||||
|  | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/cache-storage.service'; | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
| import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; | ||||
| import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| import { Injectable, Logger } from '@nestjs/common'; | ||||
|  | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/cache-storage.service'; | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
| import { InjectObjectMetadataRepository } from 'src/engine/object-metadata-repository/object-metadata-repository.decorator'; | ||||
| import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; | ||||
|   | ||||
| @@ -2,8 +2,8 @@ import { Injectable, Logger } from '@nestjs/common'; | ||||
|  | ||||
| import { Any } from 'typeorm'; | ||||
|  | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/cache-storage.service'; | ||||
| import { InjectCacheStorage } from 'src/engine/core-modules/cache-storage/decorators/cache-storage.decorator'; | ||||
| import { CacheStorageService } from 'src/engine/core-modules/cache-storage/services/cache-storage.service'; | ||||
| import { CacheStorageNamespace } from 'src/engine/core-modules/cache-storage/types/cache-storage-namespace.enum'; | ||||
| import { TwentyORMManager } from 'src/engine/twenty-orm/twenty-orm.manager'; | ||||
| import { ConnectedAccountWorkspaceEntity } from 'src/modules/connected-account/standard-objects/connected-account.workspace-entity'; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Charles Bochet
					Charles Bochet