运行 在 Google App Engine 上调用 Firebase 函数两次
Firebase functions being called twice while running on Google App Engine
我 运行 在 Google App Engine 柔性环境中使用 Firebase。我在一个节点上设置了一个 child 添加的侦听器,每次我添加一个 child 时它都会被调用两次。只有当我 运行 在 Google App Engine 上运行此代码时才会发生这种情况。如果我 运行 在本地,它会按预期运行。这是代码
// [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]
提前感谢您的帮助。
经过一段时间的测试,我明白了。此问题是由 Google App Engine 上的 运行 Firebase-Admin 引起的。本质上,您的 AppEngine 所在的每个底层 VM 都是 运行 它自己的 Firebase-Admin 实例。默认情况下,AppEngine 为每个服务维护至少两个 VM。因此,在测试中(在最小负载下),两个 VM 实例中的每一个都会调用一次 firebase 函数。
显然,没有关于此问题的文档,但 Google/Firebase 中有一个库可以解决此问题。它叫做 Firebase-Queue,可以在 NPM 上找到。我用这段代码解决了我的问题:
// [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]
我 运行 在 Google App Engine 柔性环境中使用 Firebase。我在一个节点上设置了一个 child 添加的侦听器,每次我添加一个 child 时它都会被调用两次。只有当我 运行 在 Google App Engine 上运行此代码时才会发生这种情况。如果我 运行 在本地,它会按预期运行。这是代码
// [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]
提前感谢您的帮助。
经过一段时间的测试,我明白了。此问题是由 Google App Engine 上的 运行 Firebase-Admin 引起的。本质上,您的 AppEngine 所在的每个底层 VM 都是 运行 它自己的 Firebase-Admin 实例。默认情况下,AppEngine 为每个服务维护至少两个 VM。因此,在测试中(在最小负载下),两个 VM 实例中的每一个都会调用一次 firebase 函数。
显然,没有关于此问题的文档,但 Google/Firebase 中有一个库可以解决此问题。它叫做 Firebase-Queue,可以在 NPM 上找到。我用这段代码解决了我的问题:
// [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]