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

Fix promise leaks #1311

Merged
merged 30 commits into from
Jun 4, 2019
Merged

Fix promise leaks #1311

merged 30 commits into from
Jun 4, 2019

Conversation

scottinet
Copy link
Contributor

@scottinet scottinet commented May 28, 2019

Description

The functions exposed by the notifier core generate many promises that are not awaited, and whose rejections might not be handled. And this is bad practice.

But more than a bad practice, this is also a real issue because, well... hm... I'll let Node.js do the explaining:

(node:32263) UnhandledPromiseRejectionWarning: Unhandled promise rejection. 
  This error originated either by throwing inside of an async function without a 
  catch block, or by rejecting a promise which was not handled with .catch(). 
  (rejection id: 1)
(node:32263) [DEP0018] DeprecationWarning: Unhandled promise rejections are 
  deprecated. In the future, promise rejections that are not handled will 
  terminate the Node.js process with a non-zero exit code.

That kind of warning doesn't look nice in Kuzzle's logs, not mentioning the potential issue this might cause if Node.js starts crashing on unhandled promise rejections.

How to test

Check the unit tests logs: no more warnings 🎉

@codecov
Copy link

codecov bot commented May 28, 2019

Codecov Report

Merging #1311 into 1-dev will increase coverage by <.01%.
The diff coverage is 89.62%.

Impacted file tree graph

@@            Coverage Diff            @@
##            1-dev   #1311      +/-   ##
=========================================
+ Coverage   93.79%   93.8%   +<.01%     
=========================================
  Files          98      98              
  Lines        6967    6991      +24     
=========================================
+ Hits         6535    6558      +23     
- Misses        432     433       +1
Impacted Files Coverage Δ
lib/api/core/auth/tokenManager.js 91.07% <100%> (+0.5%) ⬆️
lib/api/controllers/realtimeController.js 96.77% <100%> (+0.1%) ⬆️
lib/api/core/hotelClerk.js 92.97% <100%> (+1.35%) ⬆️
lib/api/controllers/documentController.js 99.16% <100%> (+0.04%) ⬆️
lib/api/core/notifier.js 72.93% <70.83%> (-0.67%) ⬇️

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update d23e5df...2b337aa. Read the comment docs.

.then(() => this.engine.createOrReplace(modifiedRequest))
.then(_response => {
response = _response;
return this.kuzzle.indexCache.add(
Copy link
Contributor

Choose a reason for hiding this comment

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

I didn't understand why it's needed to add the index and the collection to the cache 🤔
If they did not already exists, Kuzzle will have reject the request and if they exists, they are already in the cache (populated at startup or added when creating the collection)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I didn't pay attention to that line, since it was already there. But now that you mention it, I can't find why this would be useful.

That line was added by a 3-years old PR and my best guess is that, at that time, it was useful to put in cache the indexes/collections created directly in ES while Kuzzle was running to prevent false negatives.

This is not useful anymore since the index cache now features a hotreload mechanism.

So I'll remove it. Good catch 👍

Copy link
Contributor

@benoitvidis benoitvidis left a comment

Choose a reason for hiding this comment

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

I agree we need to handle rejections issued by the notifier but I am a little concerned with 2 points:

  1. Waiting for the Promise chain to resolve will have an impact on Kuzzle response time. I understand Koncorde is fast and we let the protocols handle the final dispatch without waiting for it but still, we have to wait for quite a bunch of operations, including some possible pipes from plugins.
  2. I will check but it is not very clear to me if we cover all the cases where the notifier could raise an error while being sure it won't eventually be sent to the end-user.

I did not think yet on how we can tackle these possible issues or whether they are acceptable or not. What do you think?

@scottinet
Copy link
Contributor Author

scottinet commented Jun 4, 2019

@benoitvidis > the first issue is not that straightforward: what kind of performances are we measuring?
This might impact the response times of API requests where the real-time engine is involved, because now Kuzzle responds only when notifications are actually computed and submitted to the network layer.
But in the other hand, that means that we free up a request slot only after all promises are settled. And this might solve a backpressure problem, where promises generated by the real-time engine can pile up in the event loop because we didn't wait before processing another request from the buffer.
So, my take on this is that:

  1. it might have a slight negative impact on API response times where real-time is involved
  2. it might have a slight positive impact on notifications delay
  3. it might prevent Kuzzle's event loop from being saturated

I'm using the conditional here, because in fact, I couldn't see any impact when I ran our benchmarks. So these considerations are theoretical, as far as I can see at least, and that's probably because the real-time engine is a lot faster than, say, checking user rights.

About the second issue: I'm not sure, but I think that we probably will have new errors appearing once the new Kuzzle version is released, because the warnings we got came from unhandled promise rejections.
So, after this PR, those errors should still be unhandled I guess, but at least they should now be properly logged or returned to requesting users, so we should now be able to fix those.

@scottinet
Copy link
Contributor Author

Re-reading my answer, I agree that there are unknows with this PR. Do you know how we could be a bit more sure of the outcomes?
On my side, I'll try to see if I can think of something...

Copy link
Contributor

@benoitvidis benoitvidis left a comment

Choose a reason for hiding this comment

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

OK, I had not thought about the back-pressure issue and the fact the benchmarks do not show any difference is a good news :)

@benoitvidis benoitvidis merged commit 430806b into 1-dev Jun 4, 2019
@benoitvidis benoitvidis deleted the fix-promise-leaks branch June 4, 2019 12:13
scottinet pushed a commit that referenced this pull request Jun 6, 2019
## What does this PR do ?

Fix notifier issue introduced by #1311
Kuzzle notifier is instanciated before the services are and `notifier.cache` and `storage` properties were set to `undefined`.

### How should this be manually tested?

```
bash features/run.sh
```
@Aschen Aschen mentioned this pull request Jun 14, 2019
Aschen added a commit that referenced this pull request Jun 14, 2019
Release 1.8.0

Bug fixes

    [ #1311 ] Fix promise leaks (scottinet)
    [ #1298 ] Fix disabled protocol initialization (Aschen)
    [ #1297 ] Fix timeouts on plugin action returing the request (benoitvidis)
    [ #1288 ] Fix an error when trying a non-partial bulk update (scottinet)
    [ #1286 ] Allows bulk inserts on aliases (benoitvidis)
    [ #1282 ] Scan keys on redis cluster (benoitvidis)
    [ #1279 ] Users must be authenticated to use auth:logout (scottinet)

New features

    [ #1315 ] Add the new Vault module to handle encrypted application secrets (Aschen)
    [ #1302 ] Add write and mWrite (Aschen)
    [ #1305 ] Add pipes & hooks wildcard event (thomasarbona)

Enhancements

    [ #1318 ] Add a maximum ttl to auth:login (benoitvidis)
    [ #1301 ] Upgrade the WebSocket libraries (scottinet)
    [ #1308 ] Events triggering refactor (scottinet)
    [ #1300 ] Collection specifications methods cloisoned to a collection (thomasarbona)
    [ #1295 ] Improve validation error messages (benoitvidis)
    [ #1292 ] Throw an error when the realtime controller is invoked by plugin developers (benoitvidis)
    [ #1257 ] Add ability to define mapping policy for new fields (Aschen)
    [ #1291 ] Fix --help on subcommands (Yoann-Abbes)
    [ #1289 ] Handle ping/pong packets (scottinet)
    [ #1273 ] Fix incomplete access logs (scottinet)

Others

    [ #1317 ] Add ps dependency to plugin-dev Docker image for pm2 (benoitvidis)
    [ #1312 ] Check that .kuzzlerc.sample is well-formed (scottinet)
    [ #1299 ] Add Kuzzle Nightly & Redis 3 and 4 test (alexandrebouthinon)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

6 participants