要生成的存储资源的Firebase Cloud Express队列



我有一个存储在Firestore集合中的大型数据集和一个Nodejs express应用程序(公开为firebase functions.https.onRequest(,该应用程序具有一个端点,允许用户查询该数据集并下载大量数据。

我需要从端点返回CSV格式的数据。因为有很多数据,所以我希望避免每次访问端点时都进行大型数据库读取。

我当前的端点是这样做的:

  1. 用户通过请求范围内文档的数据库查询达到端点
  2. 查询被散列为一个文件名。例如query_;startRange"_"endRange";。csv
  3. 检查Firebase存储,查看此查询以前是否运行过

如果csv已经存在:

  1. 返回一个302重定向到带有签名url的csv文件

如果csv不存在:

  1. 对Firestore集合运行查询
  2. 将数据转换为适当的CSV格式
  3. 将新CSV上载到Firebase存储
  4. 返回一个302重定向到带有签名url的新生成的csv文件

这个过程目前运行得很好,只是我已经预见到了一个问题。对于大型查询,CSV生成阶段大约需要20秒,并且同一请求同时被多个用户命中的可能性很高。

我想构建某种排队系统,这样,如果X个用户同时到达端点,只有第一个请求触发新CSV的生成,其他(X-1(请求将被排队,然后在生成CSV后解决。

我目前已经研究了firebase队列,该队列似乎已被弃用,并且不打算与Cloud函数一起使用。我也见过其他库,比如p-queue,但我不确定我是否理解它如何与Firebase Cloud函数一起工作,以及如何为许多请求启动单独的实例。

我认为在您的场景中,队列方法不能很好地与云函数配合使用。队列不能在一个函数中实现,因为多个实例彼此不了解,因此队列需要在某种专用服务器中实现,IMO无法实现使用云功能的目的,因为队列和处理都可以在同一服务器中运行。

我建议在Firestore中有一个集合来跟踪已请求的查询。这样,即使CSV文件仍然没有保存在Storage上,您也可以检查某个函数实例是否已经在创建它,然后您可以休眠该函数,直到操作完成并返回签名的url。总的来说,算法可能看起来有点像这样:

# Python PseudoCode
if csv_in_storage():
return signed_url()
if query_in_firestore():
while True:
sleep(X)
if csv_in_storage():
return signed_url()
try:
add_query_firestore()
csv = create_csv()
upload_csv(csv)
return signed_url()
except Exception:
while True:
sleep(X)
if csv_in_storage():
return signed_url()

最后的try/catch是存在的,因为如果两个函数同时尝试将同一文档写入Firestore,add_query_firestore操作最终可能会失败。尽管如此,这也是一个好消息,因为你知道CSV的创建正在进行中,你可以等待它完成。

请记住,上面的伪代码只是为了说明这个想法,保持while True的原样可能会导致无限循环和函数超时,这很糟糕:(。

我最终使用了一个类似Happy Monad建议的解决方案来解决这个问题。我使用的是nodejs管理SDK,但想法类似。

Firestore中有一个集合,用于跟踪已执行的查询Queries。当用户到达端点时,我调用admindoc("Queries/<queryId>").create()方法。这个方法只会在查询文档不存在的情况下创建它,所以如果我先检查现有的查询,我可以避免并行请求之间的竞争条件。

接下来,请求启动一个onSnapshot侦听器,侦听它试图创建的查询。该查询具有一个以created开头的status字段。onSnapshot只有在状态更改为complete后才会解析。

我有CCD_ 10数据库触发器监听";查询/*";。此数据库触发器处理请求的查询,并将查询状态更新为complete。在查询已经存在的情况下,状态已经处于complete状态,因此onSnapshot立即解析。

最新更新