Skip to content

Commit

Permalink
fix(apollo-usage-report): wait for hashing schema before preparing th…
Browse files Browse the repository at this point in the history
…e report (#3647)

* fix(apollo-usage-report): wait for hashing schema before preparing the report

* Less dif

* F

* Ignore when the schema is not loaded yet

* F
  • Loading branch information
ardatan authored Jan 29, 2025
1 parent 4d992d5 commit 31b7754
Show file tree
Hide file tree
Showing 3 changed files with 27 additions and 17 deletions.
5 changes: 5 additions & 0 deletions .changeset/hungry-melons-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@graphql-yoga/plugin-apollo-usage-report': patch
---

Wait for setting schemaId to prevent race condition
21 changes: 9 additions & 12 deletions packages/plugins/apollo-inline-trace/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { GraphQLError, ResponsePath } from 'graphql';
import {
createGraphQLError,
isAsyncIterable,
mapMaybePromise,
Plugin,
YogaInitialContext,
YogaLogger,
Expand Down Expand Up @@ -168,18 +169,12 @@ export function useApolloInstrumentation(options: ApolloInlineTracePluginOptions
},
onRequest({ request }): void | Promise<void> {
if (options.ignoreRequest) {
const res$ = options.ignoreRequest(request);
if (typeof res$ === 'boolean') {
if (res$) {
return;
// @ts-expect-error - Types are not aligned
return mapMaybePromise(options.ignoreRequest(request), shouldIgnore => {
if (!shouldIgnore) {
setNewContext(request);
}
} else {
return res$.then(shouldIgnore => {
if (!shouldIgnore) {
setNewContext(request);
}
});
}
});
}
setNewContext(request);
},
Expand Down Expand Up @@ -227,7 +222,9 @@ export function useApolloInstrumentation(options: ApolloInlineTracePluginOptions
const reqCtx = ctxForReq.get(request);
if (!reqCtx) return;
// onResultProcess will be called only once since we disallow async iterables
if (reqCtx.stopped) throw new Error('Trace stopped multiple times');
if (reqCtx.stopped) {
logger.debug('Trace stopped multiple times');
}

reqCtx.stopped = true;
},
Expand Down
18 changes: 13 additions & 5 deletions packages/plugins/apollo-usage-report/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
import { DocumentNode, getOperationAST, Kind, printSchema, stripIgnoredCharacters } from 'graphql';
import {
isAsyncIterable,
Maybe,
Plugin,
YogaInitialContext,
YogaLogger,
YogaServer,
type FetchAPI,
type Maybe,
type Plugin,
type PromiseOrValue,
type YogaInitialContext,
} from 'graphql-yoga';
import { Report } from '@apollo/usage-reporting-protobuf';
import {
Expand Down Expand Up @@ -79,6 +80,7 @@ export function useApolloUsageReport(options: ApolloUsageReportOptions = {}): Pl
WeakMap<Request, ApolloUsageReportRequestContext>,
];

let schemaIdSet$: Promise<void> | undefined;
let schemaId: string;
let yoga: YogaServer<Record<string, unknown>, Record<string, unknown>>;
const logger = Object.fromEntries(
Expand Down Expand Up @@ -120,12 +122,17 @@ export function useApolloUsageReport(options: ApolloUsageReportOptions = {}): Pl
},
onSchemaChange({ schema }) {
if (schema) {
hashSHA256(printSchema(schema)).then(id => {
schemaIdSet$ = hashSHA256(printSchema(schema), yoga.fetchAPI).then(id => {
schemaId = id;
schemaIdSet$ = undefined;
});
}
},

onRequestParse(): PromiseOrValue<void> {
return schemaIdSet$;
},

onParse() {
return function onParseEnd({ result, context }) {
const ctx = ctxForReq.get(context.request)?.traces.get(context);
Expand Down Expand Up @@ -167,7 +174,8 @@ export function useApolloUsageReport(options: ApolloUsageReportOptions = {}): Pl

for (const trace of reqCtx.traces.values()) {
if (!trace.schemaId || !trace.operationKey) {
throw new TypeError('Misformed trace, missing operation key or schema id');
logger.debug('Misformed trace, missing operation key or schema id');
continue;
}

const clientName = clientNameFactory(request);
Expand Down

0 comments on commit 31b7754

Please sign in to comment.