调用Firebase可调用云函数(onCall)时,前端出现“超过最后期限”的错误。
我知道我必须返回一个Promise,以便该函数知道何时清除自身,但仍然无法正常工作。
60秒后,“超过最后期限”被扔到前端,但是该功能继续在服务器上运行并成功完成。所有批处理操作都将写入Firestore。
10:37:14.782 AM
syncExchangeOperations
Function execution took 319445 ms, finished with status code: 200
10:36:57.323 AM
syncExchangeOperations
Function execution started
10:36:57.124 AM
syncExchangeOperations
Function execution took 170 ms, finished with status code: 204
10:36:56.955 AM
syncExchangeOperations
Function execution started
async function syncBinanceOperations(
userId,
userExchange,
userExchangeLastOperations,
systemExchange
) {
try {
const client = Binance({
apiKey: userExchange.apiKey,
apiSecret: userExchange.privateKey
});
const batch = admin.firestore().batch();
const lastOperations = userExchangeLastOperations
? userExchangeLastOperations
: false;
const promises = [];
promises.push(
syncBinanceTrades(client, lastOperations, userId, systemExchange, batch)
);
promises.push(
syncBinanceDeposits(client, lastOperations, userId, systemExchange, batch)
);
promises.push(
syncBinanceWhitdraws(
client,
lastOperations,
userId,
systemExchange,
batch
)
);
promises.push(
updateUserExchange(userId, userExchange.id, {
lastSync: moment().format('x')
})
);
await Promise.all(promises);
return batch.commit();
} catch (error) {
return handleErrors(error);
}
}
exports.syncExchangeOperations = functions.https.onCall(
async (data, context) => {
try {
userAuthenthication(data.userId, context.auth);
let user = await getUser(data.userId);
if (!user.plan.benefits.syncExchanges) {
throw 'Operação não autorizada para o plano contratado';
}
let userExchange = await getUserExchange(data.userId, data.exchangeId);
let response = await Promise.all([
getUserLastOperations(data.userId, userExchange.exchangeId),
getSystemExchange(userExchange.exchangeId)
]);
let userExchangeLastOperations = response[0];
let systemExchange = response[1];
switch (systemExchange.id) {
case 'binance':
return syncBinanceOperations(
user.id,
userExchange,
userExchangeLastOperations,
systemExchange
);
}
} catch (error) {
return handleErrors(error);
}
}
);
如果我将此功能更改为HTTP请求,则效果很好。它等待函数完成并返回。
exports.syncExchangeOperations = functions
.runWith(runtimeOpts)
.https.onRequest((req, res) => {
return cors(req, res, async () => {
try {
let auth = await admin.auth().verifyIdToken(req.get('Authorization').split('Bearer ')[1]);
let userExchange = await getUserExchange(
auth.uid,
req.query.exchangeId
);
let response = await Promise.all([
getUserLastOperations(auth.uid, userExchange.exchangeId),
getSystemExchange(userExchange.exchangeId)
]);
let userExchangeLastOperations = response[0];
let systemExchange = response[1];
switch (systemExchange.id) {
case 'binance':
await syncBinanceOperations(
auth.uid,
userExchange,
userExchangeLastOperations,
systemExchange
);
}
res.status(200).send();
} catch (error) {
res.status(401).send(handleErrors(error));
}
});
});
答案 0 :(得分:0)
“超过最后期限”表示从客户端的角度来看,函数调用超时。默认值为60秒。
请尝试增加客户端和功能上的超时,以使它有时间在达到客户端超时之前完成。您可以通过在HttpsCallableOptions对象中指定它来完成此操作。
还尝试返回batch.commit()
以外的内容。无论该函数返回什么,都将被序列化并发送到客户端,这可能会导致问题。相反,只需await batch.commit()
然后返回可预测的内容,例如普通的JavaScript对象。
有关设置超时的信息,请参阅API文档:
答案 1 :(得分:0)
您遇到的 “deadline-exeeded” 是客户端上的 Firebase Javascript 库(不是函数本身)抛出的错误。 Firebase 文档缺乏关于如何在可调用函数上使用 functions.runWithOptions() 的文档。出于某种原因,functions().httpsCallable() 在客户端有一个内置的超时。
因此,如果您在 Node.js 函数上使用它:
exports.testFunction = functions.runWith({ timeoutSeconds: 180 }).https.onCall(async (data, ctx) => {
// Your Function Code that takes more than 60second to run
});
您需要像这样在客户端覆盖 Javascript 库 超时中的 buit:
let testFunction = firebase.functions().httpsCallable("testFunction", {timeout: 180000});
我不知道客户端内置超时的目的是什么,对我来说它没有任何意义,因为它甚至没有停止服务器上函数的执行。但由于某些内部原因,它必须存在。
注意 Node.js timeoutSeconds 的单位为 seconds 并且客户端库上的 timeout 选项在毫秒。