问题
I am running firebase in a Google App Engine Flexible environment. I have a child added listener set up at a node and it gets called twice every single time I add one child. This only happens when I'm running this code on Google App Engine. If I run it locally, it operates as expected. Here is the code
// [START app]
'use strict';
var express = require('express');
var bodyParser = require('body-parser');
var request = require('request');
var firebase = require('firebase-admin');
var app = express();
firebase.initializeApp({
credential: firebase.credential.applicationDefault(),
databaseURL: "https://myurl.firebaseio.com/"
});
var db = firebase.database();
var globalNotifications = db.ref("/globalNotifications");
var API_KEY = "myKey"; // Your Firebase Cloud Server API key
var now = new Date();
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
globalNotifications.orderByChild('processed').equalTo(0).on("child_added", function(snapshot) {
var key = snapshot.key;
var incomingNotification = snapshot.val();
var userID = incomingNotification.userID;
var notifyID = incomingNotification.notifyID;
request({
url: 'https://fcm.googleapis.com/fcm/send',
method: 'POST',
headers: {
'Content-Type' :'application/json',
'Authorization': 'key='+API_KEY
},
body: JSON.stringify({
"to" : incomingNotification.notificationID,
"priority" : "high",
"notification" : {
"body" : "someone is following you",
"title" : "You have a new follower"
}
})
}, function(error, response, body) {
if (error) { console.error(error); }
else if (response.statusCode >= 400) {
console.error('HTTP Error: '+response.statusCode+' - '+response.statusMessage);
}
else {
console.log(response.statusCode);
console.log(body);
globalNotifications.child(key).update({"processed": 1, "response": body});
}
});
});
// Start the server
var server = app.listen(process.env.PORT || '8080', function () {
console.log('App listening on port %s', server.address().port);
console.log('Press Ctrl+C to quit.');
});
// [END app]
Thanks for any help in advance.
回答1:
After testing for a while I figured it out. This issue is caused by running Firebase-Admin on Google App Engine. Essentially, every underlying VM that your AppEngine sits on is running its own instance of Firebase-Admin. AppEngine, by default, maintains at least two VMs for every service. So in testing (under minimal load) the firebase functions are being called once by each of the two VM instances.
Apparently, there is no documentation on this issue but there is a library from Google/Firebase that does solve this problem. It is called Firebase-Queue and it can be found on NPM. I solved my issue with this code:
// [START notificationsservice app]
'use strict';
var express = require('express');
var bodyParser = require('body-parser');
var request = require('request');
var rp = require('request-promise');
var admin = require('firebase-admin');
var Queue = require('firebase-queue');
var app = express();
admin.initializeApp({
credential: admin.credential.cert("serviceAccountCredentials.json"),
databaseURL: "https://<YOUR PROJECT ID HERE>.firebaseio.com/"
});
var db = admin.database();
var notifications = db.ref('/notifications');
var API_KEY = "<YOUR API KEY HERE>"
app.use(bodyParser.json());
app.use(bodyParser.urlencoded({ extended: false }));
var queue = new Queue(notifications, function(data, progress, resolve, reject) {
var incomingNotification = data;
var userID = incomingNotification.userID;
var username = incomingNotification.username;
rp({
url: 'https://fcm.googleapis.com/fcm/send',
method: 'POST',
headers: {
'Content-Type' :'application/json',
'Authorization': 'key='+API_KEY
},
body: JSON.stringify({
"to" : "/topics/follower-"+userID,
"priority": "high",
"notification" : {
"body" : username+" you have a notification",
},
"data" : {
"type" : "follower"
}
})
}).then(function(body) {
progress(100);
console.log("Notification sent."+body);
resolve();
}).catch(function(error) {
progress(21);
console.log(error);
reject();
});
setTimeout(function() {
resolve();
}, 1000);
});
// Start the server
var server = app.listen(process.env.PORT || '8080', function () {
console.log('App listening on port %s', server.address().port);
console.log('Press Ctrl+C to quit.');
});
// [END app]
来源:https://stackoverflow.com/questions/40981572/firebase-functions-being-called-twice-while-running-on-google-app-engine