sdk icon indicating copy to clipboard operation
sdk copied to clipboard

Multiple resolves from node-fetch logged as error

Open isaacjwilliams opened this issue 4 years ago • 11 comments

The Qualys integration uses the node-fetch library to make API requests. node-fetch resolves the same promise multiple times in the case of a timeout. This does not cause any problems in the integration itself, but a multipleResolves event is published and logs an error.

isaacjwilliams avatar Jan 05 '21 19:01 isaacjwilliams

Interesting. According to the implementation, it should only invoke the callback (publish / log an error) if type === 'reject', not if type === 'resolve'. Maybe I messed up the implementation?

https://github.com/JupiterOne/sdk/blob/master/packages/integration-sdk-runtime/src/logger/registerEventHandlers.ts#L21

ndowmon avatar Jan 05 '21 19:01 ndowmon

@ndowmon node-fetch rejects the promise twice. My use of the word "resolve" was "a promise callback was called"; I didn't mean to imply which callback it was. I should have made that clear, my bad.

isaacjwilliams avatar Jan 05 '21 19:01 isaacjwilliams

Also, I am working on identifying a fix in node-fetch itself since it should not be rejecting the error twice. Maybe the change we should make here is log warn instead of error for multipleResolves? I'm sure @aiwilliams has thoughts on that idea.

isaacjwilliams avatar Jan 05 '21 19:01 isaacjwilliams

I didn't myself study the multipleResolves Node docs, but if this is indeed a bad thing to do, we should certainly not log as a level: 30, but level: 50 is ideally reserved for things we should be looking to fix ASAP (who doesn't love level = 50 in CloudWatch as a quick health test?), and which end up in Sentry. Did this end up in Sentry? This is not worthy of Sentry (doesn't actually break anything), and in fact is probably not a concern at all really (though it would be nice to provide a patch to node-fetch). It certainly led us to believe we had to spend half a day figuring out what was broken in the integration.

Summary: can we safely make all of these log at level: 40 so we know it's happening, don't have to fix immediately, and don't get bothered in Sentry?

aiwilliams avatar Jan 05 '21 19:01 aiwilliams

My only question is - would making that change reduce all multiple resolves to level: 40, or could this change be scoped to target only the node-fetch known issue? I'd fear making a change that affects all multipleResolves events and stops sending others to sentry.

ndowmon avatar Jan 05 '21 19:01 ndowmon

It sounds like multipleResolves was an error in the context where this feature was developed, so we should keep it as level: 50 and get the broken libraries patched ASAP, and perhaps have the ability to register a filter to the logger so the skipping is in the integration that uses node-fetch until the patched version is in place.

aiwilliams avatar Jan 05 '21 20:01 aiwilliams

OK then, I think the work for this issue should be to allow callers to specify error types to ignore (E.G., "FetchError"). Do y'all concur?

isaacjwilliams avatar Jan 05 '21 20:01 isaacjwilliams

@fomentia that sounds reasonable to me. I guess it will use a string to compare to the error code or something like that? I'd be cautious of any instanceof checking since, well, you know, NPM modules allow for different instances of what appears to be the same constant.

aiwilliams avatar Jan 05 '21 20:01 aiwilliams

Reading the docs for Node process.on('multipleResolves'):

This is useful for tracking potential errors in an application while using the constructor. Otherwise such mistakes are silently swallowed due to being in a Promise constructor, as multiple resolutions are silently swallowed. However, the occurrence of this event does not necessarily indicate an error. For example, [Promise.race()][] can trigger a 'multipleResolves' event.

Particularly:

the occurrence of this event does not necessarily indicate an error

This suggests to me that we really don't need to submit a PR to node-fetch; they're not doing anything wrong. We just don't like the logging that the SDK assumes it should do for all cases of this event. I'm not seeing a clear way to intercept this in the graph-qualys code to prevent it from bubbling to other registered listeners.

aiwilliams avatar Jan 06 '21 00:01 aiwilliams

Chatting with @ndowmon IRL, the best approach:

  1. Code the solution in the graph-qualys project so that we don't modify the SDK, nor do we only have this covered when running in our managed environment
  2. Consider instrumenting the logger.error/logger.onFailure function(s) as appropriate when execution starts to intercept this node-fetch behavior so that it isn't logged

aiwilliams avatar Jan 06 '21 15:01 aiwilliams

Put some effort into understanding multipleResolves: https://jupiterone.atlassian.net/browse/INT-1813?focusedCommentId=11574

aiwilliams avatar Oct 09 '21 17:10 aiwilliams