node-apn: Possible memory leak?

I am trying for several days to figure out the following error:

Warning: Possible EventEmitter memory leak detected. 11 wakeup listeners added. Use emitter.setMaxListeners() to increase limit
    at _addListener (events.js:259:19)
    at Connection.addListener (events.js:275:10)
    at Connection.Readable.on (_stream_readable.js:687:35)
    at Connection.once (events.js:301:8)
    at Connection._send (/opt/push/server/releases/20170202150908/node_modules/http2/lib/protocol/connection.js:356:10)
    at runCallback (timers.js:649:20)
    at tryOnImmediate (timers.js:622:5)
    at processImmediate [as _immediateCallback] (timers.js:594:5)`

After a long period of debugging (not that memory leaks warnings are debug-able), I think I found from where this error is coming from, server is up and no warnings in the last 24 hours.

I have added after this._connection:

this._connection.setMaxListeners(0);

I know this is not the solution (infinite listeners is a bad idea), but I am tired of figuring out what the hell is happening there, maybe a second pair of eyes can see the leak.

GNU/Linux NodeJS 6.9.4 NPM 3.10.10

I do not have a reproducible code that emits that warning because it happens once every now and then. If this only happens to me, then my bad, sorry.

About this issue

  • Original URL
  • State: open
  • Created 7 years ago
  • Reactions: 32
  • Comments: 104 (5 by maintainers)

Commits related to this issue

Most upvoted comments

I have just switched to Firebase.

I was getting this error as well till I added:

apnProvider.shutdown();

After I finished sending my notification. Where apnProvider is my apn.Provider

@ShaharHD In my solution I only create an apn.Provider when I need it. I falsely made the assumption that the apn.Provider was cleaned up by the garbage collector. This gave me the error in my project described by others above. “(node) warning: possible EventEmitter memory leak detected. 11 wakeup listeners added.” After I properly destroyed the apn.Provider when I wasn’t using it, I never saw this warning again. This may not be your issue, but this fixed mine.

This issue might come from 2 sources:

  1. Using too much events without removing them properly;
  2. Two much concurrency while I/O cannot handle them as quickly as possible, the queue growing bigger and bigger and eventually using up memory.

I tried to read the source code of this repo and node-http2, and spdy-http2. But, like most js code, they are quite hard to read and reason about what is what. Finally, simply give up.

I switched to golang and everything works great. It is easy to write. The code is concise and clear.

Problem still occurs on node 8.5.0

For the love of god let’s fix this… or at least have some proven workarounds that don’t involve switching to Go XD

Nope, I think it’s from NodeJS itself check here and here.

The fix will land in Node 6.10.0 …

@odedsh a workaround for now might be this:

$ node --no-warnings <file>
process.on('warning', (warning) => {
  if (warning.name == 'ExperimentalWarning' && warning.message == 'The http2 module is an experimental API.') {
    // suppressed
  } else {
    console.warn(`${warning.name}: ${warning.message}`);
  }
});

We’ve switched to https://github.com/AndrewBarba/apns2/tree/master and haven’t looked back. The code is much cleaner and simpler. It just works 😃

Anybody knows how to resolve this problem?

@florianreinhart Hi. I heard that http2 can solve this problem, and it seems that the v3.0.0-alpha1 version of this library has solved the memory leak problem? Currently, http2 has been released with the release of node.js version 10. It is no longer an experimental feature. Can you post a version that fixes this bug?

Have now been using node-apn-http2 for a while on production servers, logs are nice and quiet, and things are working fine. It’s fixed as far as I’m concerned. It’s a good excuse to also upgrade to 8.8.1+.

Good luck to the rest of you… but I wouldn’t hold my breath waiting for this issue to be resolved.

@odedsh Actually, I have released 1.1.0 of my module which has a workaround to disable the warning. See hideExperimentalHttp2Warning in the options at node-apn-http2

Sorry for hijacking this, hope it helps someone.

Confirm bug:

Node 10.16.0, apn 2.2.0

Code to reproduce:

const apn = require('apn');
const path = require('path');

if (!process.env.PASSPHRASE) {
  console.error(`PASSPHRASE envvar must be defined`);
  process.exit(-1);
}

const cert_path = path.resolve(__dirname, '../cert/prod_cert.pem');
const key_path =  path.resolve(__dirname, '../cert/prod_key.pem');

const provider = new apn.Provider({
  cert: cert_path,
  key: key_path,
  passphrase: process.env.PASSPHRASE,
  production: true,
  ca: null
});

const devicesTokens = [
  '67xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx4d',
  'C6xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx7E',
  '33xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx4e'
];

(function() {
  var note = new apn.Notification();

  note.expiry = Math.floor(Date.now() / 1000) + 3600;
  note.badge = 3;
  note.sound = "ping.aiff";
  note.alert = "\uD83D\uDCE7 \u2709 Wanna something tasty";
  note.payload = {'messageFrom': 'Hannibal Lecter'};
  note.topic = "my.product.id";

    return provider.send(note, devicesTokens).then(result => {
      console.log(' result:', JSON.stringify(result, null, 2));
    }).catch(error => {
      console.error(' error:', error);
    });
})();

Let unattended after send (yes, it sends 2 notification and waits) it shows (node:323) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 wakeup listeners added. U to increase limit after short time.

This bug still exist - a workaround is initiating a provider everytime and then shutting it off when you are done.

Something like this worked for me

import apn from 'apn';

const options = {
    token: {
         key: "path/to/APNsAuthKey_XXXXXXXXXX.p8",
         keyId: "key-id",
         teamId: "developer-team-id"
    },
    production: (process.env.NODE_ENV == "production") ? true : false
};

const sendNotification = (token) =>
   new Promise(
     (resolve,reject) => {
       let provider = new apn.Provider(options);
       let notification = new apn.Notification();

       notification.topic = "<your-app-bundle-id>";
       notification.alert = "hello world";

       provider.send(notification, token)
        .then( 
               response => {
                  provider.shutdown();
                  resolve(response)
               }
         )
        .catch( err => reject(err))
     }
   )

export default sendNotification;

it is only a temporary solution until this is solved would love to see a 2.x.x solution to this issue

Any chance of a fix for the 2.x version? Would be great for libraries that do not want to require node 8.x.x and can’t update to v3 yet 😃

new 3.0.0 alpha release as @florianreinhart mentioned gives no warning of ‘EventEmitter memory leak…’ and works fine for me. Thanks!

@jpike88 thanks for taking the time for testing http2.js I will fill an issue on https://github.com/kaazing/http2.js and attempt to reproduce. Keep you posted.

@ShaharHD Said

HTTP2 is not maintained any more it seems (just look at molnarg/node-http2#222 which is almost 6 months old - which is what this project hot-fixed some of the issues (https://github.com/node-apn/node-http2)

Further more HTTP2 was done fast and dirty it seems in a Summer of Code program … which makes it very hard to maintain IMO.

Node.JS is actually working on a new HTTP2 core at https://github.com/nodejs/http2 - but it is still in very early stages, although it started here almost a year ago.

@ShaharHD, Regarding molnarg/node-http2 that is non longer maintained, I just wanted to let you know what we have created a fork that include all the fixes for the issues know to date available on npm and github.

cc @alessiobacin, @blerest , @debjeet-sarkar, @DRSisco

The issue you refering to as been fixed here:

For full changes history on the fork:

Original Source and Fork intent

This NodeJS http2.js module version is a fork of node-http2 hosted on Github originally made by Gábor Molnár and available here: https://github.com/molnarg/node-http2

This fork of node-http2 module named http2.js starts at version 4.0.0 in case previous the repository decides to pick up work again on version 3.x.x.

We are aware that node 8.4.0 now has experimental http2 support via --expose-http2, and we will continue to support the full JavaScript implementation of http2.js at our discretion until HTTP/2 is more fully supported in a broad range of client platforms. source: https://github.com/kaazing/http2.js#original-source-and-fork-intent

More about http2.js

Note about publisher: Kaazing Corp is the company that brought to you https://websocket.org.

@florianreinhart Any chance we can get a new release out with HTTP/2 support now that Node has landed stable support? https://nodejs.org/api/http2.html#http2_http_2

@odedsh I assume you mean that using node-apn on 8.9.1 is not fixed, which it is not.

node-apn-http2 is a rewrite using native node http2 and should work properly, regardless of the warning.

@jacktuck Well, yes before I switched most of work to golang. Now node.js is only responsible for rendering templates on our production server. Since the problem could only be reproduced on production with hundreds of thousands of actual push to APNs, I’m afraid I could not touch the production server with this module. Maybe I could share the codes of using this module for actual push. Please wait several days since the codes is in a private repo and I need to remove sensitive information before making it public.

Any plan to fix this?

Hi,I add " this._connection.emit(‘wakeup’);" after here,the warning message has gone.

token based Authentication is not supported well. https://github.com/sideshow/apns2/issues/42 Guess just switch back to cert way

@alessiobacin, @blerest , @debjeet-sarkar, @DRSisco I actually looked into it. So fixing it … not that simple IMHO, for couple of reasons:

  1. HTTP2 is not maintained any more it seems (just look at molnarg/node-http2#222 which is almost 6 months old - which is what this project hot-fixed some of the issues (https://github.com/node-apn/node-http2)
  2. Further more HTTP2 was done fast and dirty it seems in a Summer of Code program … which makes it very hard to maintain IMO.
  3. Node.JS is actually working on a new HTTP2 core at https://github.com/nodejs/http2 - but it is still in very early stages, although it started here almost a year ago.

So, my personal recommendation is to do as follows:

  1. Use DB to group notifications (even a simple one like SQLite will work for this)
  2. Have a scheduled event (once every X milliseconds or seconds) which will create a new instance of node-apn send all the notifications in batch and then release the instance.

@DRSisco so you are creating and destroying new instances of apn.Provider every time you need to send a batch of notifications?

+1 node 6.10.0 apn 2.1.3

node 6.10.0, apn 2.1.3 +1