Provide a wrapper to execute command on workspace with easier devXP (#10391)
Proposal: - Add a method in ActiveWorkspaceCommand to loop over workspace safely (add counter, add try / catch, provide datasource with fresh cache, destroy datasource => as we do always do it) Also in this PR: - make sure we clear all dataSources (and not only the one on metadata version in RAM)
This commit is contained in:
@ -14,13 +14,17 @@ import {
|
||||
} from 'src/engine/twenty-orm/exceptions/twenty-orm.exception';
|
||||
import { EntitySchemaFactory } from 'src/engine/twenty-orm/factories/entity-schema.factory';
|
||||
import { CacheManager } from 'src/engine/twenty-orm/storage/cache-manager.storage';
|
||||
import { CacheKey } from 'src/engine/twenty-orm/storage/types/cache-key.type';
|
||||
import { WorkspaceCacheStorageService } from 'src/engine/workspace-cache-storage/workspace-cache-storage.service';
|
||||
|
||||
@Injectable()
|
||||
export class WorkspaceDatasourceFactory {
|
||||
private readonly logger = new Logger(WorkspaceDatasourceFactory.name);
|
||||
private cacheManager = new CacheManager<WorkspaceDataSource>();
|
||||
private cachedDatasourcePromise: Record<string, Promise<WorkspaceDataSource>>;
|
||||
private cachedDataSourcePromise: Record<
|
||||
CacheKey,
|
||||
Promise<WorkspaceDataSource>
|
||||
>;
|
||||
|
||||
constructor(
|
||||
private readonly dataSourceService: DataSourceService,
|
||||
@ -29,7 +33,7 @@ export class WorkspaceDatasourceFactory {
|
||||
private readonly workspaceMetadataCacheService: WorkspaceMetadataCacheService,
|
||||
private readonly entitySchemaFactory: EntitySchemaFactory,
|
||||
) {
|
||||
this.cachedDatasourcePromise = {};
|
||||
this.cachedDataSourcePromise = {};
|
||||
}
|
||||
|
||||
public async create(
|
||||
@ -53,16 +57,16 @@ export class WorkspaceDatasourceFactory {
|
||||
);
|
||||
}
|
||||
|
||||
const cacheKey = `${workspaceId}-${cachedWorkspaceMetadataVersion}`;
|
||||
const cacheKey: CacheKey = `${workspaceId}-${cachedWorkspaceMetadataVersion}`;
|
||||
|
||||
if (cacheKey in this.cachedDatasourcePromise) {
|
||||
return this.cachedDatasourcePromise[cacheKey];
|
||||
if (cacheKey in this.cachedDataSourcePromise) {
|
||||
return this.cachedDataSourcePromise[cacheKey];
|
||||
}
|
||||
|
||||
const creationPromise = (async (): Promise<WorkspaceDataSource> => {
|
||||
try {
|
||||
const result = await this.cacheManager.execute(
|
||||
cacheKey as '`${string}-${string}`',
|
||||
cacheKey,
|
||||
async () => {
|
||||
this.logger.log(
|
||||
`Creating workspace data source for workspace ${workspaceId} and metadata version ${cachedWorkspaceMetadataVersion}`,
|
||||
@ -178,22 +182,23 @@ export class WorkspaceDatasourceFactory {
|
||||
|
||||
return result;
|
||||
} finally {
|
||||
delete this.cachedDatasourcePromise[cacheKey];
|
||||
delete this.cachedDataSourcePromise[cacheKey];
|
||||
}
|
||||
})();
|
||||
|
||||
this.cachedDatasourcePromise[cacheKey] = creationPromise;
|
||||
this.cachedDataSourcePromise[cacheKey] = creationPromise;
|
||||
|
||||
return creationPromise;
|
||||
}
|
||||
|
||||
public async destroy(workspaceId: string): Promise<void> {
|
||||
const cachedWorkspaceMetadataVersion =
|
||||
await this.workspaceCacheStorageService.getMetadataVersion(workspaceId);
|
||||
const cacheKeys = (
|
||||
Object.keys(this.cachedDataSourcePromise) as CacheKey[]
|
||||
).filter((key) => key.startsWith(`${workspaceId}`));
|
||||
|
||||
await this.cacheManager.clearKey(
|
||||
`${workspaceId}-${cachedWorkspaceMetadataVersion}`,
|
||||
);
|
||||
for (const cacheKey of cacheKeys) {
|
||||
await this.cacheManager.clearKey(cacheKey);
|
||||
}
|
||||
}
|
||||
|
||||
private async getWorkspaceMetadataVersionFromCache(
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
import { isDefined } from 'twenty-shared';
|
||||
|
||||
type CacheKey = `${string}-${string}`;
|
||||
import { CacheKey } from 'src/engine/twenty-orm/storage/types/cache-key.type';
|
||||
|
||||
type AsyncFactoryCallback<T> = () => Promise<T | null>;
|
||||
|
||||
@ -52,6 +52,9 @@ export class CacheManager<T> {
|
||||
await onDelete?.(cachedValue);
|
||||
this.cache.delete(cacheKey);
|
||||
}
|
||||
// TODO: remove this once we have debug on prod
|
||||
// eslint-disable-next-line no-console
|
||||
console.log('Datasource cache size: ', this.cache.size);
|
||||
}
|
||||
|
||||
async clear(onDelete?: (value: T) => Promise<void> | void): Promise<void> {
|
||||
|
||||
@ -0,0 +1 @@
|
||||
export type CacheKey = `${string}-${string}`;
|
||||
@ -50,8 +50,15 @@ export class TwentyORMGlobalManager {
|
||||
return repository;
|
||||
}
|
||||
|
||||
async getDataSourceForWorkspace(workspaceId: string) {
|
||||
return await this.workspaceDataSourceFactory.create(workspaceId, null);
|
||||
async getDataSourceForWorkspace(
|
||||
workspaceId: string,
|
||||
failOnMetadataCacheMiss = true,
|
||||
) {
|
||||
return await this.workspaceDataSourceFactory.create(
|
||||
workspaceId,
|
||||
null,
|
||||
failOnMetadataCacheMiss,
|
||||
);
|
||||
}
|
||||
|
||||
async destroyDataSourceForWorkspace(workspaceId: string) {
|
||||
|
||||
Reference in New Issue
Block a user