node-apn: AssertionError: false == true in node-http2 lib/protocol/connection.js

We’re seeing this error fairly frequently in production after updating to node-apn 2.1.2:

AssertionError: false == true
    at Connection._send (/home/ec2-user/node/node_modules/http2/lib/protocol/connection.js:343:9)
    at Immediate.wrapped (/home/ec2-user/node/node_modules/newrelic/lib/transaction/tracer/index.js:183:28)
    at runCallback (timers.js:637:20)
    at tryOnImmediate (timers.js:610:5)
    at processImmediate [as _immediateCallback] (timers.js:582:5)

Obviously, real bad news having an uncaught exception thrown inside a Promise like this.

It looks like node-apn is using a branch of node-http2 that recently changed the behaviour of that method (https://github.com/node-apn/node-http2/pull/1), might be a smoking gun what’s causing this?

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 12
  • Comments: 41 (8 by maintainers)

Most upvoted comments

I think we should +1 in node-http2 repository https://github.com/molnarg/node-http2/issues/228

I have same problem too when i send many push notifications at the same time with node@6.9.1 and node@7.2.0

Downgrade to node@4.2.3 and apn@2.1.1 helped me

Sorry, somehow I missed the updates to this.

@florianreinhart I went ahead and opened PRs against your forked node-http2 since the ones in molnarg/node-http2 have had no action: https://github.com/node-apn/node-http2/pull/2 https://github.com/node-apn/node-http2/pull/3

I am using this as a workaround but it’s somewhat slow (about a minute to send 100,000). Anyone have ideas to improve speed? Also seeing a lot of warnings with this saying (node:46158) Warning: Possible EventEmitter memory leak detected. 11 wakeup listeners added. Use emitter.setMaxListeners() to increase limit but it still works.

db.apns_full_view.find({}, {}, (err, apnses) => {
    if (err) {
        return console.error('Could not find apnses')
    }
    var apnsIds = []
    var batchStart = 0
    var batchSize = 100
    apnses.forEach(function(apns) {
        apnsIds.push(apns.apns_id)
    })
    process.setMaxListeners(0)

    function sendMore() {
        var currBatch = apnsIds.slice(batchStart, batchStart + batchSize)
        batchStart += batchSize
        console.log(batchStart, currBatch.length, apnsIds.length)
        apnProvider.send(new apn.Notification({
            alert: 'Hello world!',
        }), currBatch).then((responses) => {
            console.log('Sent push to ' + currBatch.length)
            if (currBatch.length > 0) {
                setTimeout(sendMore, 50)
            }
        }).catch((err) => console.error(err))
    }
    sendMore()
})

Have done some more digging into this and it looks like that PR isn’t to blame - the issue is something to do with the flow frame/window stuff in node-http2 and sending the alert to too many tokens at once is what provokes it.

Dispatch an alert to 1,000 tokens and the assertion fails reproducibly. Create 10 apn.Provider instances and dispatch to 100 tokens on each and so far everything goes smoothly.