【问题标题】:firebase admin failing to query large itemsfirebase 管理员无法查询大型项目
【发布时间】:2018-03-12 14:47:25
【问题描述】:

对于大型项目,使用 firebase admin 从云函数中的集合中检索数据失败。我用来从云函数中查询选择的示例代码如下

admin.database().orderByChild('mmyyyy').equalTo(month).once('value');

当我尝试检索 10600 个项目(试图找出原因)时,此调用失败。在谷歌控制台中有这个日志,但没有其他东西可以为我指明正确的方向

textPayload:  "Function execution took 18547 ms, finished with status: 'response error'"   

在多次尝试失败后,我决定尝试使用 firebase sdk 在客户端上执行此调用,如下所示:

result = await firebase.database().ref(`transactions`).orderByChild('mmyyyy').equalTo(month).once('value');

这在客户端上完美运行,没有错误,并返回我的所有项目 17000 个(此 json 的大小为 26MB)。

为什么会这样?是否有任何未记录的限制?

注意: 我将云函数内存增加到 1gb,超时时间增加到 5 分钟,但没有帮助。

这里是完整的示例代码

const admin = require('firebase-admin');
var functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);

const cors = require('cors')({
    "origin": "*",
    "methods": "POST,GET",
    "allowedHeaders": "Content-Type,uid,agence,month,course,raceType,raceNumber,status",
    "preflightContinue": false,
    "optionsSuccessStatus": 204
});

function _findTransactions(agence, month, course, raceType, raceNumber, status) {
    return new Promise((resolve, reject) => {
        try {
            let db = admin.database();

            let findPromise = db.ref(`transactions`).orderByChild('mmyyyy').equalTo(month).once('value');

            findPromise.then((result) => {

                let transactions = result.val();

                //removed business logic

                resolve(transactions);
            }).catch((err) => {
                console.log(err);
                reject(err);
            });
        } catch (error) {
            console.log(error);
            reject(error);
        }
    });
}

exports.findTransactions = functions.https.onRequest((req, res) => {
    let uid;
    try {
        cors(req, res, () => {
            uid = req.headers.uid;
            let agence = req.headers.agence;
            let month = req.headers.month;
            let course = req.headers.course;
            let raceType = req.headers.raceType;
            let raceNumber = req.headers.raceNumber;
            let status = req.headers.status;

            if (req.method !== 'GET') {
                return handleResponse(req, res, 403);
            }

            if (!uid || uid == null || uid == undefined) {
                return handleResponse(req, res, 401);
            }

            _validateUserId(uid, ['central_cashier', 'admin'])
                .then(() => {
                    _findTransactions(agence, month, course, raceType, raceNumber, status)
                        .then((result) => {
                            return handleResponse(req, res, 200, result);
                        }).catch((error) => {
                            return handleResponse(req, res, 500);
                        });
                }).catch((error) => {
                    return handleResponse(req, res, 401);
                });
        });
    } catch (error) {
        return handleError(res, uid, error);
    }
});

【问题讨论】:

  • 您能否分享出现此问题的完整最小功能代码?
  • 我看到了同样的问题。我使用 Google Datastore 作为 GCF 的后端。当查询很小(Function execution took 23318 ms, finished with status: 'response error' 并且客户端浏览器从服务器收到 502 错误。将 GCF 内存增加到 1GB 并将客户端 (axios) 超时增加到 4 分钟并没有帮助。
  • 如果我将实体数组切片()为 10,000 个元素,一切正常。注销 Express res 对象:看起来也不错。我也在响应中返回 CORS 标头。我正在使用“简单”CORS(无飞行前选项)
  • 还尝试使用 Node.js 8 (Beta) 选项部署我的功能。没有帮助。
  • 在尝试返回大型 json 字符串时遇到与 Python 3.7 Cloud Functions 相同的问题。

标签: firebase firebase-realtime-database google-cloud-functions firebase-admin


【解决方案1】:

您的有效负载太大,如您所说,是exceeding the quota for Google Cloud Functions

想到两个选项:

  • 压缩负载。 压缩文件,然后将其发送到客户端。使用 Zlib 模块中内置的 NodeJS,这很容易,;
  • 设置虚拟机。虚拟机不受这些限制。

【讨论】:

    【解决方案2】:

    我进行了一些测试并得出结论,当查询产生大量结果(即许多 Datastore 实体)时,Google Cloud Functions (GCF) 会执行某种超时或“中止”操作。有关一些背景信息,请参阅附加到此问题的我的 cmets。

    tl;dr 我创建了自己的 Express.js 网络服务器并在其上运行了我的 GCF 代码。

    这是我测试它的方式:我创建了一个带有 http/https 并启用了 Datastore API 的 ubuntu 实例。在我的实例上,我安装了 Node、Express,并让一个基本的 https 服务器正常工作(自签名证书工作正常,因为这只是测试一个 api 后端服务)。然后我将我的 GCF 代码(在 GCF 中失败的函数)复制粘贴到我的最小 Express 网络服务器中。我让我的 React 应用程序使用我的实例,这触发了一个查询,导致超过 32,000 个数据存储实体。我的 GCF 函数使用datastore.runQuery() 发送查询,这很常见。

    花了大约一分钟,但最终所有 32,000 个实体都由 Express 提供服务,并在 React 应用程序(浏览器)中加载,没有出现任何错误。

    一个基本的 Express 路由调用我的 GCF 函数:

    app.post('/foo', (req, res) => {
      myCloudFunction(req, res);
    })
    
    const myCloudFunction = (req, res) => {
      // Inspects req, queries Datastore, and returns the results.
    };
    

    对于这个测试,我的 React 应用程序只指向 https://mydomain.example.com:3000/foo (因为我的 Express 服务器侦听端口 3000)。

    因此,对于我的应用程序来说,GCF 似乎不够好,除非我向应用程序添加分页(这在路线图上)。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-05-11
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-03-29
      • 2021-02-04
      • 2020-05-16
      • 2011-12-28
      相关资源
      最近更新 更多