Direct graphql execution (#18759)
On top of [previous closed PR](https://github.com/twentyhq/twenty/pull/18713) from @FelixMalfait : - add a schema-creation-skipping optimization - extract a handler-per-operation pattern, - add runtime input validation guards, - integrate with the standard workspace cache - add gql-style error handling To do/optimize/check : - gql parsing and null backfilling ## Intro This PR introduces a **direct GraphQL execution path** that bypasses per-workspace GraphQL schema generation for workspace data queries (CRUD on user-defined objects like companies, people, tasks, etc.). ## Why In the current architecture, every workspace gets its own dynamically-generated GraphQL schema reflecting its custom objects and fields. This costs **~20MB of RAM per workspace per pod** and takes time to build. For a multi-tenant SaaS with thousands of workspaces, this is a significant infrastructure cost and a latency bottleneck (especially on cold starts or cache misses). The insight is that most workspace queries (`findMany`, `createOne`, `updateOne`, etc.) don't actually *need* the full schema — they can be routed directly to the existing Common API query runners by parsing the GraphQL AST and matching resolver names against object metadata. The schema is only truly needed for introspection, subscriptions, or queries that mix core and workspace resolvers. ## How It Works 1. A Yoga `onRequest` plugin intercepts incoming GraphQL requests 2. It parses the query AST and checks if all top-level fields map to generated workspace resolvers (e.g. `findManyCompanies`, `createOnePerson`) 3. If yes, it executes them directly against the query runners, skipping schema generation entirely 4. If the query contains introspection, subscriptions, or core-only resolvers, it falls through to the normal path 5. Even for mixed queries it can't fully handle, it sets `skipWorkspaceSchemaCreation` to avoid building the schema when unnecessary The whole thing is gated behind the `IS_DIRECT_GRAPHQL_EXECUTION_ENABLED` feature flag for safe incremental rollout. **Net effect**: dramatically lower memory footprint and faster response times for the vast majority of workspace API calls. --------- Co-authored-by: Félix Malfait <felix@twenty.com>
This commit is contained in:
+4
@@ -2,6 +2,8 @@ import { type QueryFailedError } from 'typeorm';
|
||||
|
||||
import { CommonQueryRunnerException } from 'src/engine/api/common/common-query-runners/errors/common-query-runner.exception';
|
||||
import { commonQueryRunnerToGraphqlApiExceptionHandler } from 'src/engine/api/common/common-query-runners/utils/common-query-runner-to-graphql-api-exception-handler.util';
|
||||
import { GraphqlDirectExecutionException } from 'src/engine/api/graphql/direct-execution/errors/graphql-direct-execution.exception';
|
||||
import { graphqlDirectExecutionToGraphqlApiExceptionHandler } from 'src/engine/api/graphql/direct-execution/utils/graphql-direct-execution-to-graphql-api-exception-handler.util';
|
||||
import { GraphqlQueryRunnerException } from 'src/engine/api/graphql/graphql-query-runner/errors/graphql-query-runner.exception';
|
||||
import { graphqlQueryRunnerExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/graphql-query-runner-exception-handler.util';
|
||||
import { workspaceExceptionHandler } from 'src/engine/api/graphql/workspace-query-runner/utils/workspace-exception-handler.util';
|
||||
@@ -45,6 +47,8 @@ export const workspaceQueryRunnerGraphqlApiExceptionHandler = (
|
||||
return apiKeyGraphqlApiExceptionHandler(error);
|
||||
case error instanceof ThrottlerException:
|
||||
return throttlerToGraphqlApiExceptionHandler(error);
|
||||
case error instanceof GraphqlDirectExecutionException:
|
||||
return graphqlDirectExecutionToGraphqlApiExceptionHandler(error);
|
||||
default:
|
||||
throw error;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user