缓慢、不可靠的Firebase云功能
在我正在构建的应用程序中,用户可以请求一个单词,该应用程序将转到在线牛津词典API以获取定义、发音等。我正在使用Firebase云函数进行HTTP请求,并将响应写入Cloud Firestore。有时它工作得很慢。十分之九的数据未写入Firestore缓慢、不可靠的Firebase云功能,firebase,google-cloud-firestore,google-cloud-functions,Firebase,Google Cloud Firestore,Google Cloud Functions,在我正在构建的应用程序中,用户可以请求一个单词,该应用程序将转到在线牛津词典API以获取定义、发音等。我正在使用Firebase云函数进行HTTP请求,并将响应写入Cloud Firestore。有时它工作得很慢。十分之九的数据未写入Firestore const functions = require('firebase-functions'); const admin = require('firebase-admin'); const request = require('request'
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const request = require('request'); // node module to send HTTP requests
admin.initializeApp();
exports.oxford_English_US = functions.firestore.document('Users/{userID}/English_American/Word_Request').onUpdate((change, context) => {
console.log(change.before.data());
console.log(change.after.data());
console.log(context.params.userID);
if (change.after.data().word != undefined) {
let options = {
url: 'https://od-api.oxforddictionaries.com/api/v1/entries/en/' + change.after.data().word + '/pronunciations%3Bregions%3Dus',
headers: {
"Accept": "application/json",
'app_id': 'TDK',
'app_key': 'swordfish'
}
};
function callback(error, response, body) {
console.log(response.statusCode);
if (error) {
console.log(error)
}
if (!error && response.statusCode == 200) {
var word = JSON.parse(body);
console.log(word);
admin.firestore().collection('Users').doc(context.params.userID).collection('English_American').doc('Word_Response').set({
'metadata': word.metadata,
'results': word.results
})
.then(function() {
console.log("Document written.");
})
.catch(function(error) {
console.log("Error writing document: ", error);
})
}
}
request(options, callback);
} else {
console.log("change.after.data().word === undefined");
}
return 0;
}))
以下是一个函数调用的日志:
12:55:12.780 PM oxford_English_US { metadata: { provider: 'Oxford University Press' }, results: [ { id: 'to', language: 'en', lexicalEntries: [Object], type: 'headword', word: 'to' } ] }
12:55:12.480 PM oxford_English_US 200
12:55:09.813 PM oxford_English_US Function execution took 3888 ms, finished with status: 'ok'
12:55:09.739 PM oxford_English_US bcmrZDO0X5N6kB38MqhUJZ11OzA3
12:55:09.739 PM oxford_English_US { word: 'to' }
12:55:09.732 PM oxford_English_US { word: 'have' }
12:55:05.926 PM oxford_English_US Function execution started
该函数在四秒钟内执行。函数完成执行三秒钟后,“200”状态代码返回,其中包含数据。数据从未写入Firestore
看起来云函数没有等待HTTP响应
下面是另一个函数日志,其中云函数似乎在发送HTTP请求之前已完成执行:
1:02:29.319 PM oxford_English_US Function execution took 3954 ms, finished with status: 'ok'
1:02:29.218 PM oxford_English_US bcmrZDO0X5N6kB38MqhUJZ11OzA3
1:02:29.218 PM oxford_English_US { word: 'to' }
1:02:29.213 PM oxford_English_US { word: 'the' }
1:02:25.365 PM oxford_English_US Function execution started
是否有更好的用于发送HTTP请求的节点模块<代码>请求具有以下语法:
request(options, callback);
我宁愿返回一个承诺,而不是回调。我将节点模块
request
更改为request promise
。它现在执行起来既可靠又快速。这是我的新代码:
const functions = require('firebase-functions');
const admin = require('firebase-admin');
const rp = require('request-promise');
admin.initializeApp();
exports.oxford_English_US = functions.firestore.document('Users/{userID}/English_American/Word_Request').onUpdate((change, context) => {
if (change.after.data().word != undefined) {
let options = {
uri: 'https://od-api.oxforddictionaries.com/api/v1/entries/en/' + change.after.data().word + '/pronunciations%3Bregions%3Dus',
headers: {
"Accept": "application/json",
'app_id': 'TDK',
'app_key': 'swordfish'
},
json: true
};
rp(options)
.then(function (word) {
admin.firestore().collection('Users').doc(context.params.userID).collection('English_American').doc('Word_Response').set({
'metadata': word.metadata,
'results': word.results
})
.then(function() {
console.log("Document written.");
})
.catch(function(error) {
console.log("Error writing document: ", error);
})
})
.catch(function (error) {
console.log(error);
})
} else {
console.log("change.after.data().word === undefined");
}
return 0;
});
您的谷歌云功能应该始终返回一个承诺。如果您未能返回承诺,您将面临这样一种情况:在代码完成之前,应用程序容器可能会被拆除 根据您的示例代码:
exports.oxford_English_US = functions.firestore.document('Users/{userID}/English_American/Word_Request').onUpdate((change, context) => {
return new Promise(function(resolve, reject) {
// put your code here and resolve() or reject() based on outcome
});
}
从Firebase YouTube频道(2.Background Triggers-return a promise)“当函数中的挂起工作完成时,您必须返回一个已实现或被拒绝的承诺。这让云函数知道何时可以安全地清理函数调用并继续下一个调用。”
我认为您仍然会面临同样的“有时它会起作用”问题。请参阅本页上我的答案。另外,请参阅Doug Stevenson的“学习云函数中HTTP触发器的JavaScript承诺(第1部分)-Firecasts”,因为这是一个非常有用的旁注,您可以使用admin.firestore().collection('Users')。then()嵌套在rp(选项)中。then()。您可以将这些链接在一起,将一个结果传递给下一个,以避免所谓的末日金字塔式的承诺嵌套。
返回新承诺与有何不同。然后
和捕获
?这两种方法都会返回承诺;这是一个数字。即使它不存在,您仍然需要显式返回值,否则它将返回未定义的值,而不是承诺值。