Improve performances (#14869)

## Improvements

- Add logs to all gql operations and rest calls to help debug CPU issues
on the backend. These are temporary and should be removed
- Remove nested relations from workflowVersions load (used to add manual
triggers in the side bar). On some workspaces this call result in a
response of 4MB which is heavy on CPU
- Investigated Redis Usage ==> made a few improvements, we are should
still migrate to the new cache service once available
- investigated db calls in messaging / calendar fetch list + workflow
enqueue run cron jobs. Everything seems to be properly batched
This commit is contained in:
Charles Bochet
2025-10-03 17:22:03 +02:00
committed by GitHub
parent f973a1bcdb
commit c5cdf45f85
19 changed files with 308 additions and 199 deletions
@@ -0,0 +1,90 @@
import { Injectable, Logger } from '@nestjs/common';
import { logger } from '@sentry/node';
import { isDefined } from 'twenty-shared/utils';
import {
TwentyORMException,
TwentyORMExceptionCode,
} from 'src/engine/twenty-orm/exceptions/twenty-orm.exception';
type CacheResult<T, U> = {
version: T;
data: U;
};
@Injectable()
export class GetDataFromCacheWithRecomputeService<T, U> {
private cache = new Map<string, CacheResult<T, U>>();
logger = new Logger(GetDataFromCacheWithRecomputeService.name);
constructor() {}
getFromCacheWithRecompute = async ({
workspaceId,
getCacheData,
getCacheVersion,
recomputeCache,
cachedEntityName,
exceptionCode,
}: {
workspaceId: string;
getCacheData: (workspaceId: string) => Promise<U | undefined>;
getCacheVersion: (workspaceId: string) => Promise<T | undefined>;
recomputeCache: (params: { workspaceId: string }) => Promise<void>;
cachedEntityName: string;
exceptionCode: TwentyORMExceptionCode;
}): Promise<CacheResult<T, U>> => {
let cachedVersion: T | undefined;
let cachedData: U | undefined;
cachedVersion = await getCacheVersion(workspaceId);
const cacheKey = `${workspaceId}-${cachedVersion}`;
const cachedValue = this.cache.get(cacheKey);
if (cachedValue) {
return cachedValue;
}
cachedData = await getCacheData(workspaceId);
if (!isDefined(cachedData) || !isDefined(cachedVersion)) {
logger.warn(
`Triggering cache recompute for ${cachedEntityName} (workspace ${workspaceId})`,
{
cachedVersion,
cachedData,
},
);
await recomputeCache({ workspaceId });
cachedData = await getCacheData(workspaceId);
cachedVersion = await getCacheVersion(workspaceId);
if (!isDefined(cachedData) || !isDefined(cachedVersion)) {
logger.warn(
`Data still missing after recompute for ${cachedEntityName} (workspace ${workspaceId})`,
{
cachedVersion,
cachedData,
},
);
throw new TwentyORMException(
`${cachedEntityName} not found after recompute for workspace ${workspaceId} (missingData: ${!isDefined(cachedData)}, missingVersion: ${!isDefined(cachedVersion)})`,
exceptionCode,
);
}
}
this.cache.set(cacheKey, {
version: cachedVersion,
data: cachedData,
});
return {
version: cachedVersion,
data: cachedData,
};
};
}