Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remove access to process.env from hot code paths #5657

Merged
merged 7 commits into from
Sep 30, 2021
Merged
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
4 changes: 3 additions & 1 deletion packages/apollo-datasource-rest/src/RESTDataSource.ts
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@ export interface CacheOptions {
export type Body = BodyInit | object;
export { Request };

const NODE_ENV = process.env.NODE_ENV;

export abstract class RESTDataSource<TContext = any> extends DataSource {
httpCache!: HTTPCache;
context!: TContext;
Expand Down Expand Up @@ -282,7 +284,7 @@ export abstract class RESTDataSource<TContext = any> extends DataSource {
request: Request,
fn: () => Promise<TResult>,
): Promise<TResult> {
if (process.env.NODE_ENV === 'development') {
if (NODE_ENV === 'development') {
Comment on lines -285 to +287
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not clear in the diff, but this is for the trace method. A production environment would still pay the cost for this check, even though it would eventually evaluate to false and skip the tracing.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess this is fine. RESTDataSource hasn't been actively maintained in a little while (the current Apollo Server team has not yet ramped up on it; it's basically an entirely unrelated project that is very loosely coupled to Apollo Server). I don't know if anyone depends on the ability to set process.env.NODE_ENV at runtime (eg, potentially after this file is imported) and have it take effect. But if it breaks people we can revert it.

// We're not using console.time because that isn't supported on Cloudflare
const startTime = Date.now();
try {
Expand Down
22 changes: 9 additions & 13 deletions packages/apollo-server-core/src/ApolloServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,10 @@ export class ApolloServerBase<
// The constructor should be universal across all environments. All environment specific behavior should be set by adding or overriding methods
constructor(config: Config<ContextFunctionParams>) {
if (!config) throw new Error('ApolloServer requires options.');
this.config = config;
this.config = {
...config,
nodeEnv: config.nodeEnv ?? process.env.NODE_ENV,
};
moberegger marked this conversation as resolved.
Show resolved Hide resolved
moberegger marked this conversation as resolved.
Show resolved Hide resolved
const {
context,
resolvers,
Expand All @@ -170,7 +173,7 @@ export class ApolloServerBase<
mockEntireSchema,
experimental_approximateDocumentStoreMiB,
...requestOptions
} = config;
} = this.config;
moberegger marked this conversation as resolved.
Show resolved Hide resolved

// Setup logging facilities
if (config.logger) {
Expand Down Expand Up @@ -206,16 +209,7 @@ export class ApolloServerBase<
this.experimental_approximateDocumentStoreMiB =
experimental_approximateDocumentStoreMiB;

// Allow tests to override process.env.NODE_ENV. As a bonus, this means
// we're only reading the env var once in the constructor, which is faster
// than reading it over and over as each read is a syscall. Note that an
// explicit `__testing_nodeEnv__: undefined` overrides a set environment
// variable!
const nodeEnv =
'__testing_nodeEnv__' in config
? config.__testing_nodeEnv__
: process.env.NODE_ENV;
const isDev = nodeEnv !== 'production';
const isDev = this.config.nodeEnv !== 'production';

// We handle signals if it was explicitly requested, or if we're in Node,
// not in a test, not in a serverless framework, and it wasn't explicitly
Expand All @@ -224,7 +218,9 @@ export class ApolloServerBase<
this.stopOnTerminationSignals =
typeof stopOnTerminationSignals === 'boolean'
? stopOnTerminationSignals
: isNodeLike && nodeEnv !== 'test' && !this.serverlessFramework();
: isNodeLike &&
this.config.nodeEnv !== 'test' &&
!this.serverlessFramework();

// if this is local dev, introspection should turned on
// in production, we can manually turn introspection on by passing {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ describe('runHttpQuery', () => {
query: '{ testString }',
},
options: {
debug: false,
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was required to avoid returning a stack trace, which the test didn't expect. Without running through ApolloServer first, the nodeEnv stuff never runs, so it doesn't get setup correctly for this test. This avoids that.

schema,
schemaHash: generateSchemaHash(schema),
},
Expand Down
2 changes: 1 addition & 1 deletion packages/apollo-server-core/src/graphqlOptions.ts
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ export interface GraphQLServerOptions<
plugins?: ApolloServerPlugin[];
documentStore?: InMemoryLRUCache<DocumentNode>;
parseOptions?: ParseOptions;
__testing_nodeEnv__?: string | undefined;
nodeEnv?: string;
}

export type DataSources<TContext> = {
Expand Down
15 changes: 7 additions & 8 deletions packages/apollo-server-core/src/runHttpQuery.ts
Original file line number Diff line number Diff line change
Expand Up @@ -114,11 +114,13 @@ export function throwHttpGraphQLError<E extends Error>(
);
}

const NODE_ENV = process.env.NODE_ENV ?? '';

export async function runHttpQuery(
handlerArguments: Array<any>,
request: HttpQueryRequest,
moberegger marked this conversation as resolved.
Show resolved Hide resolved
): Promise<HttpQueryResponse> {
function debugFromNodeEnv(nodeEnv: string | undefined) {
function debugFromNodeEnv(nodeEnv: string = NODE_ENV) {
return nodeEnv !== 'production' && nodeEnv !== 'test';
}

Expand All @@ -129,18 +131,15 @@ export async function runHttpQuery(
// The options can be generated asynchronously, so we don't have access to
// the normal options provided by the user, such as: formatError,
// debug. Therefore, we need to do some unnatural things, such
// as use NODE_ENV to determine the debug settings
// as use NODE_ENV to determine the debug settings. Please note that this
// will not be sensitive to any runtime changes made to NODE_ENV.
return throwHttpGraphQLError(500, [e as Error], {
debug: debugFromNodeEnv(process.env.NODE_ENV),
debug: debugFromNodeEnv(),
});
}

if (options.debug === undefined) {
const nodeEnv =
'__testing_nodeEnv__' in options
? options.__testing_nodeEnv__
: process.env.NODE_ENV;
options.debug = debugFromNodeEnv(nodeEnv);
options.debug = debugFromNodeEnv(options.nodeEnv);
moberegger marked this conversation as resolved.
Show resolved Hide resolved
}

// TODO: Errors thrown while resolving the context in
Expand Down
9 changes: 1 addition & 8 deletions packages/apollo-server-core/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,5 @@ export interface Config<ContextFunctionParams = any> extends BaseConfig {
experimental_approximateDocumentStoreMiB?: number;
stopOnTerminationSignals?: boolean;
apollo?: ApolloConfigInput;
// Apollo Server only uses process.env.NODE_ENV to determine defaults for
// other behavior which have other mechanisms of setting explicitly. Sometimes
// our tests want to test the exact logic of how NODE_ENV affects defaults;
// they can set this parameter, but there's no reason to do so other than for
// tests. Note that an explicit `__testing_nodeEnv__: undefined` means "act as
// if the environment variable is not set", whereas the absence of
// `__testing_nodeEnv__` means to honor the environment variable.
Comment on lines -102 to -108
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Didn't think that this comment was necessary anymore, since I suppose you can consider nodeEnv a first class option now.

__testing_nodeEnv__?: string | undefined;
nodeEnv?: string;
}
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ describe('apollo-server-express', () => {
const { httpServer } = await createServer({
typeDefs,
resolvers,
__testing_nodeEnv__: undefined, // default landing page
nodeEnv: '', // default landing page
});

await request(httpServer)
Expand Down Expand Up @@ -265,7 +265,7 @@ describe('apollo-server-express', () => {
throw new AuthenticationError('valid result');
},
// Stack trace not included for NODE_ENV=test
__testing_nodeEnv__: undefined,
nodeEnv: '',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -296,7 +296,7 @@ describe('apollo-server-express', () => {
},
},
// Stack trace not included for NODE_ENV=test
__testing_nodeEnv__: undefined,
nodeEnv: '',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -326,7 +326,7 @@ describe('apollo-server-express', () => {
},
},
},
__testing_nodeEnv__: 'production',
nodeEnv: 'production',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -355,7 +355,7 @@ describe('apollo-server-express', () => {
},
},
},
__testing_nodeEnv__: 'production',
nodeEnv: 'production',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ describe('apollo-server-fastify', () => {
const { httpServer } = await createServer({
typeDefs,
resolvers,
__testing_nodeEnv__: undefined, // default landing page
nodeEnv: '', // default landing page
});

await request(httpServer)
Expand Down Expand Up @@ -283,7 +283,7 @@ describe('apollo-server-fastify', () => {
throw new AuthenticationError('valid result');
},
// Stack trace not included for NODE_ENV=test
__testing_nodeEnv__: undefined,
nodeEnv: '',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -314,7 +314,7 @@ describe('apollo-server-fastify', () => {
},
},
// Stack trace not included for NODE_ENV=test
__testing_nodeEnv__: undefined,
nodeEnv: '',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -344,7 +344,7 @@ describe('apollo-server-fastify', () => {
},
},
},
__testing_nodeEnv__: 'production',
nodeEnv: 'production',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -373,7 +373,7 @@ describe('apollo-server-fastify', () => {
},
},
},
__testing_nodeEnv__: 'production',
nodeEnv: 'production',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down
10 changes: 5 additions & 5 deletions packages/apollo-server-hapi/src/__tests__/ApolloServer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ describe('non-integration tests', () => {
const { httpServer } = await createServer({
typeDefs,
resolvers,
__testing_nodeEnv__: undefined, // default landing page
nodeEnv: '', // default landing page
});

await request(httpServer)
Expand Down Expand Up @@ -288,7 +288,7 @@ describe('non-integration tests', () => {
throw new AuthenticationError('valid result');
},
// Stack trace not included for NODE_ENV=test
__testing_nodeEnv__: undefined,
nodeEnv: '',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -319,7 +319,7 @@ describe('non-integration tests', () => {
},
},
// Stack trace not included for NODE_ENV=test
__testing_nodeEnv__: undefined,
nodeEnv: '',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -349,7 +349,7 @@ describe('non-integration tests', () => {
},
},
},
__testing_nodeEnv__: 'production',
nodeEnv: 'production',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -378,7 +378,7 @@ describe('non-integration tests', () => {
},
},
},
__testing_nodeEnv__: 'production',
nodeEnv: 'production',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down
18 changes: 9 additions & 9 deletions packages/apollo-server-integration-testsuite/src/ApolloServer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -248,7 +248,7 @@ export function testApolloServer<AS extends ApolloServerBase>(
const { url: uri } = await createApolloServer({
schema,
stopOnTerminationSignals: false,
__testing_nodeEnv__: undefined,
nodeEnv: '',
});

const apolloFetch = createApolloFetch({ uri });
Expand All @@ -262,7 +262,7 @@ export function testApolloServer<AS extends ApolloServerBase>(
const { url: uri } = await createApolloServer({
schema,
stopOnTerminationSignals: false,
__testing_nodeEnv__: 'production',
nodeEnv: 'production',
});

const apolloFetch = createApolloFetch({ uri });
Expand All @@ -281,7 +281,7 @@ export function testApolloServer<AS extends ApolloServerBase>(
schema,
introspection: true,
stopOnTerminationSignals: false,
__testing_nodeEnv__: 'production',
nodeEnv: 'production',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -979,7 +979,7 @@ export function testApolloServer<AS extends ApolloServerBase>(
],
debug: true,
stopOnTerminationSignals: false,
__testing_nodeEnv__: undefined,
nodeEnv: '',
...constructorOptions,
});

Expand Down Expand Up @@ -1595,7 +1595,7 @@ export function testApolloServer<AS extends ApolloServerBase>(
typeDefs,
resolvers,
stopOnTerminationSignals: false,
__testing_nodeEnv__: undefined,
nodeEnv: '',
context: () => {
throw new AuthenticationError('valid result');
},
Expand Down Expand Up @@ -1653,7 +1653,7 @@ export function testApolloServer<AS extends ApolloServerBase>(
},
},
stopOnTerminationSignals: false,
__testing_nodeEnv__: 'production',
nodeEnv: 'production',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -1683,7 +1683,7 @@ export function testApolloServer<AS extends ApolloServerBase>(
},
},
stopOnTerminationSignals: false,
__testing_nodeEnv__: 'production',
nodeEnv: 'production',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -1714,7 +1714,7 @@ export function testApolloServer<AS extends ApolloServerBase>(
},
},
stopOnTerminationSignals: false,
__testing_nodeEnv__: 'development',
nodeEnv: 'development',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -2922,7 +2922,7 @@ export function testApolloServer<AS extends ApolloServerBase>(
})),
],
// dev mode, so we get the local landing page
__testing_nodeEnv__: undefined,
nodeEnv: '',
};
}

Expand Down
10 changes: 5 additions & 5 deletions packages/apollo-server-koa/src/__tests__/ApolloServer.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,7 @@ describe('apollo-server-koa', () => {
const { httpServer } = await createServer({
typeDefs,
resolvers,
__testing_nodeEnv__: undefined, // default landing page
nodeEnv: '', // default landing page
});

await request(httpServer)
Expand Down Expand Up @@ -254,7 +254,7 @@ describe('apollo-server-koa', () => {
throw new AuthenticationError('valid result');
},
// Stack trace not included for NODE_ENV=test
__testing_nodeEnv__: undefined,
nodeEnv: '',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -285,7 +285,7 @@ describe('apollo-server-koa', () => {
},
},
// Stack trace not included for NODE_ENV=test
__testing_nodeEnv__: undefined,
nodeEnv: '',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -315,7 +315,7 @@ describe('apollo-server-koa', () => {
},
},
},
__testing_nodeEnv__: 'production',
nodeEnv: 'production',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down Expand Up @@ -344,7 +344,7 @@ describe('apollo-server-koa', () => {
},
},
},
__testing_nodeEnv__: 'production',
nodeEnv: 'production',
});

const apolloFetch = createApolloFetch({ uri });
Expand Down