Firebase 函数需要几分钟才能写入 Firestore

Firebase functions take MINUTES to write in Firestore

我正在构建一个移动应用程序并在某些操作(如 userCreate)上触发一些 Firebase 函数来执行对第三方服务的 API 调用,然后在 Firestore 数据库中写入一些内容。

理论上一切正常,但在实践中,API 调用非常快(即使在冷启动情况下),但数据库写入可能需要几分钟才能完成(如果确实如此,我怀疑有时耗时太长超时)。

由于 API 调用工作得很好,在某些情况下数据库写入也是如此,我怀疑这仅仅是由于 非常 糟糕的异步管理我,因为我对 JS 一无所知。

这里有两个与此问题有关的示例函数,只是为了展示它是在我在 onCreate 或 HTTPS 上触发函数时发生的。

onCreate 函数

const functions = require("firebase-functions");
const axios = require('axios')

// The Firebase Admin SDK to access the Firestore.
const admin = require('firebase-admin');
admin.initializeApp();

// Third party service credentials generation during onCreate request
exports.

buildCredentials = functions.auth.user().onCreate((user) => {


// Request to Third party to generate an Client Access Token
axios({
    method: "post",
    url: "https://api.ThirdParty.com/api/v1/oauth/token",
    data: "client_id=xxx&client_secret=yyy&grant_type=client_credentials&scope=all:all",
    headers: { "Content-Type": "application/x-www-form-urlencoded" },
  })
    .then(function (response) {
      //handle success
      console.log('new user created: ')
      console.log(user.id);
      console.log(response.data);
    
      // We write a new document in the users collection with the user ID and the Client Access Token
      const db = admin.firestore();
      const newUser = {
        uid: user.uid,
        clientAccessToken: response.data.access_token
      };

      db.collection('users').doc(user.uid).set(newUser)
      .catch(function (error) {
      //handle error
      console.log(error);
    });

    })
    .catch(function (response) {
      //handle error
      console.log(response);
    });
})  

HTTPS onCall 函数

exports.paymentRequest = functions.https.onCall(async (data, context) => {
    const clientAccessToken = data.clientAccessToken;
    const recipientIban = data.recipientIban;
    const recipientName = data.recipientName;
    const paymentDescription = data.paymentDescription;
    const paymentReference = data.paymentReference;
    const productPrice = parseInt(data.productPrice);
    const uid = data.uid;

    const jsonData = {
        "destinations": [
                {
                    "accountNumber": recipientIban,
                    "type": "iban"          
                }
            ],
            "amount": productPrice,
            "currency": "EUR",
            "market": "FR",
            "recipientName": recipientName,
            "sourceMessage": paymentDescription,
            "remittanceInformation": {
                "type": "UNSTRUCTURED",
                "value": paymentReference
                },
            "paymentScheme": "SEPA_INSTANT_CREDIT_TRANSFER"
    };
    (async function(){
    response = await axios({
        method: "post",
        url: "https://api.ThirdParty.com/api/v1/pay",
        headers: { 
            'Content-Type': 'application/json',
            Accept: 'application/json',
            Authorization: `Bearer ${clientAccessToken}`,},
        data: jsonData,
        })

        // We write a the payment request ID in the user's document
        const db = admin.firestore();
        const paymentRequestID = response.data.id;

        db.collection('users').doc(uid).set({
            paymentRequestID: paymentRequestID
        }, { merge: true })
        .catch(function (error) {
            //handle error
            console.log(error);
            });
        console.log(response.data)
        return response.data
    })()
})

我认为这是一个异步问题是否正确? 还是 Firebase/Firestore 问题?

谢谢

您没有return通过异步方法(axios()set())return 承诺,可能会产生一些“不稳定”的云行为函数.

正如您将在来自官方 Firebase video series 的关于“JavaScript Promises”的三个视频中看到的那样,您必须 return 后台触发 Cloud Function 的 Promise 或值,以向平台表明它已完成,并避免它在异步操作完成之前终止或在工作完成后继续 运行。

以下改编应该可以解决问题(未经测试):

onCreate 函数:

buildCredentials = functions.auth.user().onCreate((user) => {

    // Request to Third party to generate an Client Access Token
    return axios({
        method: "post",
        url: "https://api.ThirdParty.com/api/v1/oauth/token",
        data: "client_id=xxx&client_secret=yyy&grant_type=client_credentials&scope=all:all",
        headers: { "Content-Type": "application/x-www-form-urlencoded" },
      })
        .then(function (response) {
          //handle success
          console.log('new user created: ')
          console.log(user.id);
          console.log(response.data);
        
          // We write a new document in the users collection with the user ID and the Client Access Token
          const db = admin.firestore();
          const newUser = {
            uid: user.uid,
            clientAccessToken: response.data.access_token
          };
    
          return db.collection('users').doc(user.uid).set(newUser)
    
        })
        .catch(function (response) {
          //handle error
          console.log(response);
          return null;
        });
    })  

可调用函数:

exports.paymentRequest = functions.https.onCall(async (data, context) => {
    
    try {
        
        const clientAccessToken = data.clientAccessToken;
        const recipientIban = data.recipientIban;
        const recipientName = data.recipientName;
        const paymentDescription = data.paymentDescription;
        const paymentReference = data.paymentReference;
        const productPrice = parseInt(data.productPrice);
        const uid = data.uid;
    
        const jsonData = {
            // ...
        };
        const response = await axios({
            method: "post",
            url: "https://api.ThirdParty.com/api/v1/pay",
            headers: {
                'Content-Type': 'application/json',
                Accept: 'application/json',
                Authorization: `Bearer ${clientAccessToken}`,
            },
            data: jsonData,
        })
    
        // We write a the payment request ID in the user's document
        const db = admin.firestore();
        const paymentRequestID = response.data.id;
    
        await db.collection('users').doc(uid).set({
            paymentRequestID: paymentRequestID
        }, { merge: true })
            
        console.log(response.data)
        return response.data
        
    } catch (error) {
        
        // See https://firebase.google.com/docs/functions/callable#handle_errors    
    
    }
    
})