0

Ich versuche einen Benachrichtigungsserver in node.js zu erstellen, der die Benachrichtigungen von einer Datenbank erhält, ihre Nutzdaten bearbeitet, sie über Firebase Cloud Messaging sendet und dann ihren Status bearbeitet in der Datenbank.Programm wird nicht beendet wenn Firebase Cloud Messaging gesendet wird sendToDevice

Javascript ist nicht meine Hauptsprache, also hoffe ich, dass es in diesem Code nicht viele Missverständnisse gibt.

Um dies zu tun, verwende ich einige Promises und ein Promise.all.

Derzeit ist das Problem, wenn ich firebase.admin.messaging().sendToDevice aufrufen, beendet meine App nie die Ausführung. Hier

ist der Code:

main.js:

'use strict'; 
global.basePath = __dirname + '/'; 

    const conf = require('./config/config'), 
     db  = require('./lib/database'), 
     builder = require('./notify/builder'); 

const gender = conf.genderId[process.argv[2]], 
     type = conf.typeId[process.argv[3]], 
     confSql = conf.inc.prod ? conf.mysql.prod : conf.mysql.dev, 
     database = new db.database(confSql); 

const notify = new Promise(
    (resolve, reject) => { 
     if (typeof(gender) !== 'number' && typeof(type) !== 'number') { 
      return reject('Error: gender and type are mandatory'); 
     } 
     resolve(); 
    } 
); 


function main() { 

    notify 
    //Get the notifications from DB - They are already group by user 
    .then(() => { return database.getNotifications(gender, type); }) 
    //Set the payload, send to Firebase, and update the status in DB 
    // <-- Inside it is the call to Firebase 
    .then(rows => { return Promise.all(rows.map(builder.handleNotification)); } 
     , err => { 
      return database.close().then(() => { 
       return Promise.reject(err) 
      }); 
     } 
    ) 
    .then(() => { 
     console.log('Success ! The DB and the app must close.'); 
     database.close(); 
    }) 
    .catch(console.log.bind(console)) 
    ; 
} 


main(); 

builder.js:

'use strict'; 
const conf = require('./../config/config'), 
     sender = require('./sender'), 
     database = require('./../lib/database'); 


//This is called inside an array.map 
//It is a chain of Promises that are resolved or rejected in a Promise.all 
function handleNotification(notification){ 
    let notif = notification; 

    return Promise.resolve(setGroupPayload(notification)) 
     .then(sender.send) 
     .then(console.log) 
     .catch(error => { 
      return Promise.reject(error); 
     }); 
} 


function setGroupPayload (notification){ 

    //Do some change on notifications 
    // (...) 

    return notification; 
} 

module.exports = { 
    handleNotification: handleNotification 
}; 

database.js:

const mysql = require('mysql'); 



function Database(config) { 
    this.connection = mysql.createConnection(config); 
} 

Database.prototype.query = function query(sql, args) { 
    return new Promise((resolve, reject) => { 
     this.connection.query(sql, args, (err, rows) => { 
      if (err) 
       return reject(err); 
      resolve(rows); 
     }); 
    }); 
}; 


Database.prototype.ping = function ping(){ 
    return new Promise((resolve, reject) => { 
     this.connection.ping(err => { 
      if (err) 
       return reject(err); 
      resolve('Server responded to ping'); 
     }); 
    }); 
}; 

Database.prototype.close = function close() { 
    console.log('close connection'); 
    return new Promise((resolve, reject) => { 
     this.connection.end(err => { 
      if (err) 
       return reject(err); 
      console.log('connection closed'); 
      resolve(); 
     }); 
    }); 
}; 


Database.prototype.getNotifications = function getNotifications (gender, type) { 
    const query = `(...)`; 
    const params = [gender, type]; 

    return this.query(query, params); 
}; 

module.exports = { 
    database: Database 
}; 

Und schließlich die sender.js:

'use strict'; 
const firebase = require('./../lib/firebase-admin'); 

/** 
* 
* @param notification 
* @returns {Promise} 
*/ 
function send (notification) { 

    if (notification.message === false) { 
     return Promise.reject(["payload is empty"]); 
    } 
    if (!(notification.token && notification.token.length > 0)) { 
     return Promise.reject(["target is empty."]); 
    } 

    const options = { 
     contentAvailable: true 
    }; 

    //When this is called here, the app never ends 
    return firebase.admin.messaging().sendToDevice(notification.token, notification.message, options);/
} 


module.exports = { 
    send: send 
}; 

Ich habe von firebase.admin.messaging().sendToDevice(notification.token, notification.message, options) die folgende Antwort, die eine Promise.resolve:

[ { error: { [Error: The provided registration token is not registered. A previously valid registration token can be unregistered for a variety of reasons. See the error documentation for more details. Remove this registration token and stop using it to send messages.] errorInfo: [Object], codePrefix: 'messaging' } } ] 

Das ist richtig, weil das Token nicht gültig ist. Und ich möchte mit dieser Antwort umgehen. Aber was ich nicht verstehe, warum hört meine App nie auf? Es sieht so aus, als wären sie im Promise ein unendliches Versprechen. Alle verhindern, dass die App beendet wird.

Ich habe auch versucht die Antwort von Firebase zu handhaben und eine Promise.reject an die Versprechen Kette senden, aber ohne Erfolg ...

So ... Wo bin ich falsch? Vielen Dank an alle, die mir helfen können, diesen Fehler zu beheben.

Edit:

Ich habe eine .then() vor dem Fang in der builder.js hinzugefügt, wie @JimWright gefragt.

Und hier ist das Ergebnis:

Hier ist das Ergebnis:

{ results: [ { error: [Object] } ], 
    canonicalRegistrationTokenCount: 0, 
    failureCount: 1, 
    successCount: 0, 
    multicastId: 6057186106180078000 } 
Success ! The DB and the app must close. 
close connection 
connection closed 
+0

Try a 'dann()' vor dem Fang in 'builder.js' Zugabe - erhalten Sie das Ergebnis da? Protokollieren Sie den Fehler auch, um zu sehen, ob Sie dort etwas erhalten. –

+0

Ist das von 'then()' oder 'catch()'? –

+0

Vielen Dank für Ihre Antwort @JimWright. Ich habe den Beitrag bearbeitet. sendToDevice sendet eine Promise.resolve(). Auch wenn es einen Fehler sendet, ist es immer noch eine Lösung. – MrZog

Antwort

1

Sie sollten den Fehler werfen, der zurückgegeben wird.

sender.js

function send (notification) { 

    if (notification.message === false) { 
     return Promise.reject(new Error("payload is empty")); 
    } 
    if (!(notification.token && notification.token.length > 0)) { 
     return Promise.reject(new Error("target is empty.")); 
    } 

    const options = { 
     contentAvailable: true 
    }; 

    //When this is called here, the app never ends 
    const response = firebase.admin.messaging().sendToDevice(notification.token, notification.message, options); 
    if ('error' in response[0] and response[0]['error']) { 
     return Promise.reject(response[0]['error']); 
    ); 

    return response; 
} 

EDIT:

aus den Protokollen es Ihr Code sieht aus wie auf dem Endpunkt ausgeführt wird. Sie sollten .finally() verwenden, um alle Ihre Verbindungen zu schließen, da diese Schließung ausgeführt wird, ob die Zusage aufgelöst oder zurückgewiesen wird.

main.js

function main() { 

    notify 
    //Get the notifications from DB - They are already group by user 
    .then(() => { return database.getNotifications(gender, type); }) 
    //Set the payload, send to Firebase, and update the status in DB 
    // <-- Inside it is the call to Firebase 
    .then(rows => { return Promise.all(rows.map(builder.handleNotification)); } 
     , err => { 
      return database.close().then(() => { 
       return Promise.reject(err) 
      }); 
     } 
    ) 
    .then(() => { 
     console.log('Success!'); 
     // database.close(); 
    }) 
    .catch(console.log.bind(console)) 
    .finally(() => { 
     console.log('Closing all connections...'); 
     database.close(); 
     console.log('All connections closed.'); 
     // Execution should stop here 
    }); 
} 
+0

Niemals nicht fehlerhafte Objekte in JavaScript zurückweisen, da dies Ihre Produktions-Stack-Traces auslöschen würde. –

+0

Ich habe nur die letzten paar Zeilen hinzugefügt - ich glaube, dieser Kommentar ist einer für OP. –

+0

'Antwort' ist nur ein Pending Promise, also muss ein' .then() 'aufgerufen werden, um auf die result- und error -Eigenschaft zugreifen zu können. – MrZog

Verwandte Themen