我尝试在node.js中创建一个通知服务器,它从数据库获取通知,编辑其有效负载,通过Firebase Cloud Messaging发送,然后在数据库中编辑它们的状态。
Javascript不是我的主要语言,所以我希望他们在这段代码中没有太多误解。
为此,我使用了一些Promises和Promise.all。
目前,问题是当我拨打firebase.admin.messaging().sendToDevice
时,我的应用程序永远不会结束执行。
以下是代码:
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
};
最后,发件人.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
};
我从firebase.admin.messaging().sendToDevice(notification.token, notification.message, options)
获得了以下回复,即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' } } ]
这是正确的,因为令牌无效。我想处理这个问题。但是我不明白,为什么我的应用程序永远不会结束?看起来他们是Promise.all中的一个无休止的承诺,阻止应用程序结束。
我还尝试处理来自Firebase的响应并将Promise.reject
发送到promise链,但没有成功......
所以......我哪里错了? 非常感谢任何可以帮助我解决这个错误的人。
修改:
我在@ {JimWright问的.then()
中的抓取之前添加了builder.js
。
结果如下:
结果如下:
{ results: [ { error: [Object] } ],
canonicalRegistrationTokenCount: 0,
failureCount: 1,
successCount: 0,
multicastId: 6057186106180078000 }
Success ! The DB and the app must close.
close connection
connection closed
答案 0 :(得分:1)
你应该抛出返回的错误。
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;
}
编辑:
从日志中看起来您的代码正在执行到最后一点。您应该使用.finally()
来关闭所有连接,因为无论承诺是否得到解决或拒绝,此闭包都会运行。
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
});
}
答案 1 :(得分:0)
使用firebase管理员后是否正在调用app.delete()
函数?必须调用它来关闭连接和后台任务。
在你的主要功能中,你应该做这样的事情(我没有找到你对firebase.initializeApp()
的调用,所以我假设它在main.js文件中):
const firebase = require('firebase-admin');
const firebaseApp = FirebaseAdmin.initializeApp()
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();
firebaseApp.delete(); // Add this to finish firebase background tasks
})
.catch(console.log.bind(console))
;
}
参考文献:
How to properly exit firebase-admin nodejs script when all transaction is completed