Skip to content

Commit 493e6a7

Browse files
prastoinetiennejouan
authored andcommitted
Invalidate flat cache command (#17442)
# Introduction A command allowing to invalidate flat cache entries. Extends the active or suspended workspace coverage. ## Args ### --metadataName If provided will invalidate metadata and related metadata cache entry ( can be repeated see usage ) ### --all-metadata Will invalidate all metadata entries ## Usage example ``` npx nx command twenty-server cache:flat-cache-invalidate --metadataName viewFilter --metadataName objectMetadata ``` ``` npx nx command twenty-server cache:flat-cache-invalidate --all-metadata -w 0000-0000-0000-0000 ```
1 parent c477545 commit 493e6a7

File tree

2 files changed

+171
-0
lines changed

2 files changed

+171
-0
lines changed
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
import { InjectRepository } from '@nestjs/typeorm';
2+
3+
import { Command, Option } from 'nest-commander';
4+
import {
5+
ALL_METADATA_NAME,
6+
type AllMetadataName,
7+
} from 'twenty-shared/metadata';
8+
import { Repository } from 'typeorm';
9+
10+
import {
11+
ActiveOrSuspendedWorkspacesMigrationCommandRunner,
12+
type ActiveOrSuspendedWorkspacesMigrationCommandOptions,
13+
} from 'src/database/commands/command-runners/active-or-suspended-workspaces-migration.command-runner';
14+
import { type RunOnWorkspaceArgs } from 'src/database/commands/command-runners/workspaces-migration.command-runner';
15+
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
16+
import { DataSourceService } from 'src/engine/metadata-modules/data-source/data-source.service';
17+
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
18+
import { getMetadataFlatEntityMapsKey } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-flat-entity-maps-key.util';
19+
import { getMetadataRelatedMetadataNames } from 'src/engine/metadata-modules/flat-entity/utils/get-metadata-related-metadata-names.util';
20+
import { GlobalWorkspaceOrmManager } from 'src/engine/twenty-orm/global-workspace-datasource/global-workspace-orm.manager';
21+
22+
type FlatCacheFlushCommandOptions =
23+
ActiveOrSuspendedWorkspacesMigrationCommandOptions & {
24+
allMetadata?: boolean;
25+
};
26+
27+
@Command({
28+
name: 'cache:flat-cache-invalidate',
29+
description:
30+
'Flush flat entity cache for specific metadata names and workspaces',
31+
})
32+
export class FlatCacheInvalidateCommand extends ActiveOrSuspendedWorkspacesMigrationCommandRunner<FlatCacheFlushCommandOptions> {
33+
private metadataNames: string[] = [];
34+
private flatMapsKeysToFlush: ReturnType<
35+
typeof getMetadataFlatEntityMapsKey
36+
>[] = [];
37+
38+
constructor(
39+
@InjectRepository(WorkspaceEntity)
40+
protected readonly workspaceRepository: Repository<WorkspaceEntity>,
41+
protected readonly globalWorkspaceOrmManager: GlobalWorkspaceOrmManager,
42+
protected readonly dataSourceService: DataSourceService,
43+
private readonly flatEntityMapsCacheService: WorkspaceManyOrAllFlatEntityMapsCacheService,
44+
) {
45+
super(workspaceRepository, globalWorkspaceOrmManager, dataSourceService);
46+
}
47+
48+
@Option({
49+
flags: '--metadataName <metadataName>',
50+
description:
51+
'Metadata name(s) to flush cache for. Can be specified multiple times.',
52+
required: false,
53+
})
54+
parseMetadataName(val: string): string[] {
55+
this.metadataNames.push(val);
56+
57+
return this.metadataNames;
58+
}
59+
60+
@Option({
61+
flags: '--all-metadata',
62+
description:
63+
'Flush cache for all metadata names. Takes precedence over --metadataName.',
64+
required: false,
65+
})
66+
parseAllMetadata(): boolean {
67+
return true;
68+
}
69+
70+
override async runMigrationCommand(
71+
passedParams: string[],
72+
options: FlatCacheFlushCommandOptions,
73+
): Promise<void> {
74+
if (!options.allMetadata && this.metadataNames.length === 0) {
75+
this.logger.error(
76+
'Either --all-metadata or at least one --metadataName must be provided.',
77+
);
78+
79+
return;
80+
}
81+
82+
const validatedMetadataNames = this.validateAndExpandMetadataNames({
83+
inputMetadataNames: this.metadataNames,
84+
allMetadata: options.allMetadata,
85+
});
86+
87+
if (validatedMetadataNames === null) {
88+
return;
89+
}
90+
91+
this.flatMapsKeysToFlush = this.computeFlatMapsKeysWithRelated(
92+
validatedMetadataNames,
93+
);
94+
95+
this.logger.log(
96+
`Will flush cache for the following flat maps keys: ${this.flatMapsKeysToFlush.join(', ')}`,
97+
);
98+
99+
await super.runMigrationCommand(passedParams, options);
100+
}
101+
102+
override async runOnWorkspace({
103+
workspaceId,
104+
}: RunOnWorkspaceArgs): Promise<void> {
105+
await this.flatEntityMapsCacheService.invalidateFlatEntityMaps({
106+
workspaceId,
107+
flatMapsKeys: this.flatMapsKeysToFlush,
108+
});
109+
110+
this.logger.log(`Successfully flushed cache for workspace: ${workspaceId}`);
111+
}
112+
113+
private validateAndExpandMetadataNames({
114+
inputMetadataNames,
115+
allMetadata,
116+
}: {
117+
inputMetadataNames: string[];
118+
allMetadata?: boolean;
119+
}): AllMetadataName[] | null {
120+
const validMetadataNames = Object.keys(
121+
ALL_METADATA_NAME,
122+
) as AllMetadataName[];
123+
124+
if (allMetadata) {
125+
this.logger.log('Using all metadata names');
126+
127+
return validMetadataNames;
128+
}
129+
130+
const invalidNames = inputMetadataNames.filter(
131+
(name) => !validMetadataNames.includes(name as AllMetadataName),
132+
);
133+
134+
if (invalidNames.length > 0) {
135+
this.logger.error(
136+
`Invalid metadata name(s) provided: ${invalidNames.join(', ')}`,
137+
);
138+
this.logger.error(
139+
`Valid metadata names are: ${validMetadataNames.join(', ')}, or use --all-metadata`,
140+
);
141+
142+
return null;
143+
}
144+
145+
return inputMetadataNames as AllMetadataName[];
146+
}
147+
148+
private computeFlatMapsKeysWithRelated(
149+
metadataNames: AllMetadataName[],
150+
): ReturnType<typeof getMetadataFlatEntityMapsKey>[] {
151+
const allMetadataNamesToFlush = [
152+
...new Set([
153+
...metadataNames,
154+
...metadataNames.flatMap(getMetadataRelatedMetadataNames),
155+
]),
156+
];
157+
158+
const allFlatMapsKeys = allMetadataNamesToFlush.map(
159+
getMetadataFlatEntityMapsKey,
160+
);
161+
162+
return allFlatMapsKeys;
163+
}
164+
}

packages/twenty-server/src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.module.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
import { Module } from '@nestjs/common';
22
import { TypeOrmModule } from '@nestjs/typeorm';
33

4+
import { FlatCacheInvalidateCommand } from 'src/engine/core-modules/cache-storage/commands/flat-cache-invalidate.command';
5+
import { WorkspaceEntity } from 'src/engine/core-modules/workspace/workspace.entity';
6+
import { DataSourceModule } from 'src/engine/metadata-modules/data-source/data-source.module';
47
import { FieldMetadataEntity } from 'src/engine/metadata-modules/field-metadata/field-metadata.entity';
58
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
69
import { WorkspaceFlatFieldMetadataMapCacheService } from 'src/engine/metadata-modules/flat-field-metadata/services/workspace-flat-field-metadata-map-cache.service';
@@ -34,7 +37,9 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache
3437
@Module({
3538
imports: [
3639
WorkspaceCacheModule,
40+
DataSourceModule,
3741
TypeOrmModule.forFeature([
42+
WorkspaceEntity,
3843
ViewEntity,
3944
ViewFieldEntity,
4045
ViewFilterEntity,
@@ -66,6 +71,7 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache
6671
WorkspaceFlatPageLayoutWidgetMapCacheService,
6772
WorkspaceFlatRowLevelPermissionPredicateMapCacheService,
6873
WorkspaceFlatRowLevelPermissionPredicateGroupMapCacheService,
74+
FlatCacheInvalidateCommand,
6975
],
7076
exports: [
7177
WorkspaceManyOrAllFlatEntityMapsCacheService,
@@ -82,6 +88,7 @@ import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache
8288
WorkspaceFlatPageLayoutWidgetMapCacheService,
8389
WorkspaceFlatRowLevelPermissionPredicateMapCacheService,
8490
WorkspaceFlatRowLevelPermissionPredicateGroupMapCacheService,
91+
FlatCacheInvalidateCommand,
8592
],
8693
})
8794
export class WorkspaceManyOrAllFlatEntityMapsCacheModule {}

0 commit comments

Comments
 (0)