Refactor workspace cache service (#16208)
## Context We've recently introduced a new workspace cache service which now acts as a cache access and local storage for all workspace related data, deprecating the individual specific services. - Better performance through multiple caching/fetching strategies - Consistent data access patterns across the codebase - Reduced redis queries through MGET/MSET/PIPELINE with multiple cache keys
This commit is contained in:
+2
-1
@@ -1,10 +1,11 @@
|
||||
import { Module } from '@nestjs/common';
|
||||
|
||||
import { WorkspaceManyOrAllFlatEntityMapsCacheService } from 'src/engine/metadata-modules/flat-entity/services/workspace-many-or-all-flat-entity-maps-cache.service';
|
||||
import { WorkspaceCacheModule } from 'src/engine/workspace-cache/workspace-cache.module';
|
||||
import { WorkspaceFlatMapCacheModule } from 'src/engine/workspace-flat-map-cache/workspace-flat-map-cache.module';
|
||||
|
||||
@Module({
|
||||
imports: [WorkspaceFlatMapCacheModule],
|
||||
imports: [WorkspaceFlatMapCacheModule, WorkspaceCacheModule],
|
||||
providers: [WorkspaceManyOrAllFlatEntityMapsCacheService],
|
||||
exports: [WorkspaceManyOrAllFlatEntityMapsCacheService],
|
||||
})
|
||||
|
||||
+15
-80
@@ -1,66 +1,12 @@
|
||||
import { Injectable, Logger } from '@nestjs/common';
|
||||
|
||||
import { isDefined } from 'twenty-shared/utils';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
import { ALL_FLAT_ENTITY_MAPS_PROPERTIES } from 'src/engine/metadata-modules/flat-entity/constant/all-flat-entity-maps-properties.constant';
|
||||
import { AllFlatEntityMaps } from 'src/engine/metadata-modules/flat-entity/types/all-flat-entity-maps.type';
|
||||
import { WorkspaceFlatMapCacheRegistryService } from 'src/engine/workspace-flat-map-cache/services/workspace-flat-map-cache-registry.service';
|
||||
import { WorkspaceFlatMapCacheService } from 'src/engine/workspace-flat-map-cache/services/workspace-flat-map-cache.service';
|
||||
import { WorkspaceCacheService } from 'src/engine/workspace-cache/services/workspace-cache.service';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceManyOrAllFlatEntityMapsCacheService {
|
||||
private readonly logger = new Logger(
|
||||
WorkspaceManyOrAllFlatEntityMapsCacheService.name,
|
||||
);
|
||||
|
||||
constructor(
|
||||
private readonly cacheRegistry: WorkspaceFlatMapCacheRegistryService,
|
||||
) {}
|
||||
|
||||
private async executeActionForManyOrAllFlatEntity<
|
||||
K extends (keyof AllFlatEntityMaps)[] = (keyof AllFlatEntityMaps)[],
|
||||
>({
|
||||
action,
|
||||
flatMapsKeys,
|
||||
}: {
|
||||
flatMapsKeys: K | undefined;
|
||||
action: (args: {
|
||||
service: WorkspaceFlatMapCacheService<AllFlatEntityMaps[K[number]]>;
|
||||
flatMapKey: K[number];
|
||||
}) => Promise<void>;
|
||||
}): Promise<void> {
|
||||
const keysToProcess = isDefined(flatMapsKeys)
|
||||
? flatMapsKeys
|
||||
: ALL_FLAT_ENTITY_MAPS_PROPERTIES;
|
||||
|
||||
const results = await Promise.allSettled(
|
||||
keysToProcess.map(async (flatMapKey) => {
|
||||
try {
|
||||
const service = this.cacheRegistry.getCacheServiceOrThrow(
|
||||
flatMapKey as K[number],
|
||||
);
|
||||
|
||||
return await action({
|
||||
flatMapKey: flatMapKey,
|
||||
service,
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to run action on flat entity maps of ${flatMapKey}`,
|
||||
error,
|
||||
);
|
||||
throw error;
|
||||
}
|
||||
}),
|
||||
);
|
||||
|
||||
const failures = results.filter((result) => result.status === 'rejected');
|
||||
|
||||
if (failures.length > 0) {
|
||||
this.logger.error(`${failures.length} operations failed`);
|
||||
throw new Error(`Failed to process ${failures.length} flat entity maps`);
|
||||
}
|
||||
}
|
||||
constructor(private readonly workspaceCacheService: WorkspaceCacheService) {}
|
||||
|
||||
public async getOrRecomputeManyOrAllFlatEntityMaps<
|
||||
T extends (keyof AllFlatEntityMaps)[] = (keyof AllFlatEntityMaps)[],
|
||||
@@ -71,20 +17,10 @@ export class WorkspaceManyOrAllFlatEntityMapsCacheService {
|
||||
workspaceId: string;
|
||||
flatMapsKeys?: T;
|
||||
}): Promise<Pick<AllFlatEntityMaps, T[number]>> {
|
||||
let pickedFlatEntityMaps = {} as Pick<AllFlatEntityMaps, T[number]>;
|
||||
|
||||
await this.executeActionForManyOrAllFlatEntity({
|
||||
action: async ({ service, flatMapKey }) => {
|
||||
const cacheResult = await service.getExistingOrRecomputeFlatMaps({
|
||||
workspaceId,
|
||||
});
|
||||
|
||||
pickedFlatEntityMaps[flatMapKey] = cacheResult;
|
||||
},
|
||||
flatMapsKeys,
|
||||
});
|
||||
|
||||
return pickedFlatEntityMaps;
|
||||
return await this.workspaceCacheService.getOrRecompute(
|
||||
workspaceId,
|
||||
flatMapsKeys ?? ALL_FLAT_ENTITY_MAPS_PROPERTIES,
|
||||
);
|
||||
}
|
||||
|
||||
public async invalidateFlatEntityMaps<
|
||||
@@ -96,11 +32,10 @@ export class WorkspaceManyOrAllFlatEntityMapsCacheService {
|
||||
workspaceId: string;
|
||||
flatMapsKeys?: T;
|
||||
}): Promise<void> {
|
||||
await this.executeActionForManyOrAllFlatEntity({
|
||||
action: async ({ service }) =>
|
||||
await service.invalidateCache({ workspaceId }),
|
||||
flatMapsKeys,
|
||||
});
|
||||
await this.workspaceCacheService.invalidateAndRecompute(
|
||||
workspaceId,
|
||||
flatMapsKeys ?? ALL_FLAT_ENTITY_MAPS_PROPERTIES,
|
||||
);
|
||||
}
|
||||
|
||||
public async flushFlatEntityMaps<
|
||||
@@ -112,9 +47,9 @@ export class WorkspaceManyOrAllFlatEntityMapsCacheService {
|
||||
workspaceId: string;
|
||||
flatMapsKeys?: T;
|
||||
}): Promise<void> {
|
||||
await this.executeActionForManyOrAllFlatEntity({
|
||||
action: async ({ service }) => await service.flushCache({ workspaceId }),
|
||||
flatMapsKeys,
|
||||
});
|
||||
await this.workspaceCacheService.flush(
|
||||
workspaceId,
|
||||
flatMapsKeys ?? ALL_FLAT_ENTITY_MAPS_PROPERTIES,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user