Flat entity maps cache generic service + runner dynamically retrieving invalidating update cache + view service v2 refactor (#14508)
# Introduction Migrate previous runner only iterating on `flatObjectMetadataMaps` to `allFlatEntityMaps`. Refactored the optimistic to be handled inside the actions handler ## Workspace flat map cache Introducing a new service and registry, that will dynamically retrieve and or recompute requested cache when called ## Runner refactor Runner now dynamically invalidate updated cache at the end of the transaction close https://github.com/orgs/twentyhq/projects/1/views/8?pane=issue&itemId=129136356&issue=twentyhq%7Ccore-team-issues%7C1492 close https://github.com/orgs/twentyhq/projects/1/views/8?pane=issue&itemId=129136210&issue=twentyhq%7Ccore-team-issues%7C1494
This commit is contained in:
+7
@@ -0,0 +1,7 @@
|
||||
import { type AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
|
||||
|
||||
export const ALL_FLAT_ENTITY_MAPS_PROPERTIES = [
|
||||
'flatObjectMetadataMaps',
|
||||
'flatViewFieldMaps',
|
||||
'flatViewMaps',
|
||||
] as const satisfies (keyof AllFlatEntityMaps)[];
|
||||
+1
-1
@@ -3,7 +3,7 @@ import { type AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all
|
||||
|
||||
export const EMPTY_ALL_FLAT_ENTITY_MAPS = {
|
||||
flatObjectMetadataMaps: {
|
||||
byId: {},
|
||||
...EMPTY_FLAT_ENTITY_MAPS,
|
||||
idByNameSingular: {},
|
||||
},
|
||||
flatViewFieldMaps: EMPTY_FLAT_ENTITY_MAPS,
|
||||
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/core-modules/common/services/workspace-many-or-all-flat-entity-maps-cache.service.';
|
||||
import { WorkspaceFlatMapCacheModule } from 'src/engine/workspace-flat-map-cache/workspace-flat-map-cache.module';
|
||||
|
||||
@Module({
|
||||
imports: [WorkspaceFlatMapCacheModule],
|
||||
providers: [WorkspaceManyOrAllFlatEntityMapsCacheService],
|
||||
exports: [WorkspaceManyOrAllFlatEntityMapsCacheService],
|
||||
})
|
||||
export class WorkspaceManyOrAllFlatEntityMapsCacheModule {}
|
||||
+105
@@ -0,0 +1,105 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
|
||||
import { ALL_FLAT_ENTITY_MAPS_PROPERTIES } from 'src/engine/core-modules/common/constant/all-flat-entity-maps-properties.constant';
|
||||
import { EMPTY_ALL_FLAT_ENTITY_MAPS } from 'src/engine/core-modules/common/constant/empty-all-flat-entity-maps.constant';
|
||||
import { AllFlatEntityMaps } from 'src/engine/core-modules/common/types/all-flat-entity-maps.type';
|
||||
import {
|
||||
WorkspaceFlatMapCacheException,
|
||||
WorkspaceFlatMapCacheExceptionCode,
|
||||
} from 'src/engine/workspace-flat-map-cache/exceptions/workspace-flat-map-cache.exception';
|
||||
import { WorkspaceFlatMapCacheRegistryService } from 'src/engine/workspace-flat-map-cache/services/workspace-flat-map-cache-registry.service';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceManyOrAllFlatEntityMapsCacheService {
|
||||
private readonly logger = new Logger(
|
||||
WorkspaceManyOrAllFlatEntityMapsCacheService.name,
|
||||
);
|
||||
|
||||
constructor(
|
||||
private readonly cacheRegistry: WorkspaceFlatMapCacheRegistryService,
|
||||
) {}
|
||||
|
||||
public async getOrRecomputeManyOrAllFlatEntityMaps<
|
||||
T extends (keyof AllFlatEntityMaps)[] = (keyof AllFlatEntityMaps)[],
|
||||
>({
|
||||
flatEntities,
|
||||
workspaceId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
flatEntities?: T;
|
||||
}): Promise<Pick<AllFlatEntityMaps, T[number]>> {
|
||||
const allFlatEntityMaps: AllFlatEntityMaps = structuredClone(
|
||||
EMPTY_ALL_FLAT_ENTITY_MAPS,
|
||||
);
|
||||
|
||||
for (const flatEntityName of ALL_FLAT_ENTITY_MAPS_PROPERTIES) {
|
||||
if (isDefined(flatEntities) && !flatEntities.includes(flatEntityName)) {
|
||||
delete allFlatEntityMaps[flatEntityName];
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const service = this.cacheRegistry.getCacheService(flatEntityName);
|
||||
|
||||
if (!isDefined(service)) {
|
||||
throw new WorkspaceFlatMapCacheException(
|
||||
`No cache service found for ${flatEntityName}`,
|
||||
WorkspaceFlatMapCacheExceptionCode.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
|
||||
const result = await service.getExistingOrRecomputeFlatMaps({
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
// @ts-expect-error todo prastoin once refactored flat object metadata cache
|
||||
allFlatEntityMaps[flatEntityName] = result;
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to get flat entity maps for ${flatEntityName}`,
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
||||
return allFlatEntityMaps;
|
||||
}
|
||||
|
||||
public async invalidateFlatEntityMaps<
|
||||
T extends (keyof AllFlatEntityMaps)[] = (keyof AllFlatEntityMaps)[],
|
||||
>({
|
||||
flatEntities,
|
||||
workspaceId,
|
||||
}: {
|
||||
workspaceId: string;
|
||||
flatEntities?: T;
|
||||
}): Promise<void> {
|
||||
for (const flatEntityName of ALL_FLAT_ENTITY_MAPS_PROPERTIES) {
|
||||
if (isDefined(flatEntities) && !flatEntities.includes(flatEntityName)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
try {
|
||||
const service = this.cacheRegistry.getCacheService(flatEntityName);
|
||||
|
||||
if (!isDefined(service)) {
|
||||
throw new WorkspaceFlatMapCacheException(
|
||||
`No cache service found for ${flatEntityName}`,
|
||||
WorkspaceFlatMapCacheExceptionCode.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
|
||||
await service.invalidateCache({ workspaceId });
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to invalidate flat entity maps for ${flatEntityName}`,
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
import { type FlatViewField } from 'src/engine/core-modules/view/flat-view/types/flat-view-field.type';
|
||||
import { type FlatView } from 'src/engine/core-modules/view/flat-view/types/flat-view.type';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
|
||||
export type AllFlatEntitiesByMetadataEngineName = {
|
||||
// flatFieldMetadata: FlatFieldMetadata;
|
||||
objectMetadata: FlatObjectMetadata;
|
||||
view: FlatView;
|
||||
viewField: FlatViewField;
|
||||
};
|
||||
+3
-9
@@ -1,10 +1,4 @@
|
||||
import { type FlatViewField } from 'src/engine/core-modules/view/flat-view/types/flat-view-field.type';
|
||||
import { type FlatView } from 'src/engine/core-modules/view/flat-view/types/flat-view.type';
|
||||
import { type FlatObjectMetadata } from 'src/engine/metadata-modules/flat-object-metadata/types/flat-object-metadata.type';
|
||||
import { type AllFlatEntitiesByMetadataEngineName } from 'src/engine/core-modules/common/types/all-flat-entities-by-metadata-engine-name.type';
|
||||
|
||||
export type AllFlatEntitiesByMetadataEngineName = {
|
||||
// flatFieldMetadata: FlatFieldMetadata;
|
||||
objectMetadata: FlatObjectMetadata;
|
||||
view: FlatView;
|
||||
viewField: FlatViewField;
|
||||
};
|
||||
export type AllFlatEntities =
|
||||
AllFlatEntitiesByMetadataEngineName[keyof AllFlatEntitiesByMetadataEngineName];
|
||||
|
||||
Reference in New Issue
Block a user