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

Wrap the catch method also #367

Merged
merged 3 commits into from Jan 28, 2021
Merged

Conversation

DavidTanner
Copy link
Contributor

@DavidTanner DavidTanner commented Dec 30, 2020

The current implementation of wrapping promises doesn't handle new Promise().then(onSuccess).catch(onFailure) setups. This is causing a circular dependency in ApolloServer.

I'm having trouble creating a test case for it, but am experiencing it when running in a Lambda function.

By submitting this pull request, I confirm that my contribution is made under the terms of the Apache 2.0 license.

@srprash
Copy link
Contributor

srprash commented Jan 6, 2021

Hi @DavidTanner ! Thanks for identifying this gap. Patching the catch in addition to then is certainly required.
I would like to understand your use case better. Would it possible to post a small snippet where you're running into this issue? This may help coming up with the test case for the PR as well. I didn't understand how not having the wrapper on catch can cause the circular dependency. Can you elaborate on that and how that appears only in Lambda function?

@DavidTanner
Copy link
Contributor Author

After debugging further I've found the circular dependency is caused by how exceptions are stored on the Segment, and specifically on the Lambda facade segment.

@willarmiros
Copy link
Contributor

@DavidTanner Exceptions are not meant to be stored on segments in Lambda, the Lambda facade segment available to your function code is immutable because the Lambda service manages the real segment that you ultimately see in the X-Ray console. Indeed, all the functions of the facade segment, including addError, are stubbed out to be no-ops: https://github.com/aws/aws-xray-sdk-node/blob/dd34e7e/packages/core/lib/env/aws_lambda.js#L51-L57

While I still think this is a valid change, I'm just a bit confused on where the "circular dependency" is.

@DavidTanner
Copy link
Contributor Author

See #370 for a fix to the circular exception.

The Error gets added to the facade segment, which will never clear it off because the methods are stubbed. Using capturePromise causes the error@context to be added to the exception accross async methods. In Apollo this error gets stringified and ends up as ApolloException.originalError.error@context.segment.exception.ex where ex is originalError thus creating the cycle that causes JSON.stringify to crash.

https://github.com/apollographql/apollo-server/blob/b7a91df76acef748488eedcfe998917173cff142/packages/apollo-server-core/src/runHttpQuery.ts#L108

https://github.com/apollographql/apollo-server/blob/b7a91df76acef748488eedcfe998917173cff142/packages/apollo-server-core/src/runHttpQuery.ts#L454

It has been brought up before for them to use a different method than JSON.stringify, but that has gone nowhere.

apollographql/apollo-server#1433

@willarmiros
Copy link
Contributor

@DavidTanner thank you for the additional context. If you're willing, adding a small unit test to verify the CLS namespace is available in the catch block of a rejected promise would be appreciated. That being said, I understand we're currently lacking unit tests for this patcher so I'm willing to merge as is if you don't have the bandwidth.

@DavidTanner
Copy link
Contributor Author

I'll see what I can get together real quick @willarmiros

Copy link
Contributor

@willarmiros willarmiros left a comment

Choose a reason for hiding this comment

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

LGTM, and thanks @DavidTanner so much for adding these tests! Just a couple questions then good to merge.

logger.error();
logger.error(null);
logger.error('', null);

spies.forEach(spy => expect(spy).not.to.be.called);
spies.forEach(spy => sinon.assert.notCalled(spy));
Copy link
Contributor

Choose a reason for hiding this comment

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

Just for my knowledge, why replace some of these expects with sinon assertions?

@willarmiros
Copy link
Contributor

I'll wait for @srprash to weigh in as well before merging.

Copy link
Contributor

@srprash srprash left a comment

Choose a reason for hiding this comment

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

Looks good to me too. Thanks for adding the tests and cleaning up other bits as well. :)

@willarmiros willarmiros merged commit dc7ec53 into aws:master Jan 28, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

3 participants