NodeJS Node-apn implementation as daemon

I have a node-apn nodejs script running as a daemon on AmazonWS. The daemon runs fine and the script stays up and comes back when it goes down but I believe I am having a synchronous execution and exiting issue with node.js. When I release the process with process.exit(); even though all console.logs output saying they have sent my messages, they never are received on the phone. I decided to remove the exit and let the process "hang" after execution and all messages were sent successfully. This led me to do the following implementation using an ASYNC function, but the same result seems to be happening. Can anyone provide insight to this? There are no errors being thrown from APN or anywhere else.

function closeDB()
{ 

    connection.end(function(err) {
    if (err) {
        console.log("ERROR: " + util.inspect(err, false, 5));
        process.exit(1);
    } 

    console.log("APNS-PUSH: COMPLETED.");
});

setTimeout(function(){process.exit();}, 50);

} // End of closeDB()

function apnsError(err, notification)
{
console.log(err);
console.log(notification);
closeDB();
}  

function async(arg, callback) 
{
apnsConnection.sendNotification(arg);
console.log(arg); 
setTimeout(function() { callback(1); }, 100);
} 

/**
* Our MySQL query callback.
*/
function queryCB(err, results) 
{

//error in our all, report and exit
if (err) {
    console.log("ERROR: " + util.inspect(err, false, 5));
    closeDB();
} 

if(results.length == 0)
{
    closeDB();
}

var notes = [];
var count = 0;

try {
    for( var i = 0; i < results.length; i++ ) {
        var myDevice = new apns.Device(results[i]['udid']);

        var note = new apns.Notification();

        note.expiry = Math.floor(Date.now() / 1000) + 3600; // Expires 1 hour from now.
        note.badge = results[i]["notification_count"];
        note.sound = "ping.aiff";
        note.alert = results[i]["message"];
        note.device = myDevice;

        connection.query('UPDATE `tbl_notifications` SET `sent`=1 WHERE `id`=' + results[i]["id"] , function(err, results) {
                if(err)
                {
                    console.log("ERROR: " + util.inspect(err, false, 5));
                }
            });

        notes.push(note);
    }
} catch( err ) {
    console.log('error: ' + err)
}

console.log(notes.length);

notes.forEach(function(nNode) {
    async(nNode, function(result) {
        count++;
        if(count == notes.length) {
            closeDB();
        }
    })
});         

} // End of queryCB()

I had the same problem where killing the process also killed the open socket connections and didn't allow the notifications to be sent. The solution I came up with isn't an an ideal solution but it will work in your situation as well. I looked into the node-apn code and found that the Connection object inherited from EventEmitter so you can monitor events on the object like so:

var apnsConnection = new apn.Connection(options)

apnsConnection.sendNotification(notification)

apnsConnection.on('transmitted', function(){
    console.log("Transmitted")
    callback()
})

apnsConnection.on('error', function(){
    console.log("Error")
    callback()
})

This is monitoring the socket that the notification is sent through so I don't know how accurate it is at determining when a notification has successfully been passed off to Apple's APNS servers but it has worked pretty well for me.

The reason you are seeing this problem is that when you use #pushNotification it buffers the notification inside the module and handles sending it asynchronously.

Listening for "transmitted" is valid and this is emitted when the notification has been written to the socket. However, if your objective is to close the socket after all notifications have been sent then the easiest way to accomplish this is using the connectionTimeout property when creating your connection.

Simply set connectionTimeout to something around 1000 (milliseconds) and assuming you have no other connections open then the process will exit automatically. Or you can set an event listener on the timeout event and call process.exit() from there.