创建多个轻量级 Google Cloud Functions 的最佳实践? [英] Best practice for creating multiple lightweight Google Cloud Functions?

查看:18
本文介绍了创建多个轻量级 Google Cloud Functions 的最佳实践?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Google Cloud Functions 的工作方式似乎是:

The way it seems Google Cloud Functions works is by:

  • 您的模块位于 functions 目录中
  • 那个 functions 目录然后包含一个 package.json 文件以包含所有模块之间的共享依赖项
  • 每个模块可以包含许多导出的函数
  • google云函数和firebase函数在模块中如何处理导出函数意见不一
    • 对于 gcp,它似乎是这样工作的:模块被上传,然后你通过 web 界面或命令行指定应该从加载的模块中调用哪个导出的方法
    • 对于 firebase,它似乎是这样工作的:来自 firebase-functions 的侦听器方法返回处理程序,但也将触发器元数据附加到该处理程序.firebase-tools cli 应用程序然后需要您的本地代码,获取导出的函数,然后根据来自 firebase-functions 的附加元数据为每个导出的方法创建云函数.因此,如果您将所有云功能放在同一个模块中,那么它将为每个云功能多次部署该模块,并且为每个云功能加载整个模块,然后调用特定的导出功能.
    • your modules go inside a functions directory
    • that functions directory then contains a package.json file to contain the shared dependencies across all your modules
    • modules can contain many exported functions per module
    • google cloud functions and firebase functions have different opinions how to handle exported functions in modules
      • for gcp, it seems to work like this: the module is uploaded, and then you specify via the web interface or command line which exported method should be called from the loaded module
      • for firebase, it seems to work like this: the listener methods from firebase-functions return the handler, but also attaches to that handler the trigger meta-data. The firebase-tools cli app then requires your code locally, grabs the exported functions, then creates cloud functions for each exported method based on its attached meta-data from the firebase-functions stuff. As such, if you put all your cloud functions in the same module, then it will deploy that module multiple times for each cloud function, and for each cloud function the entire module is loaded, and then the specific exported function is called.

      这很奇怪:

      • 说即使模块 one.jstwo.js 在运行时需要不同的包,它们之间共享的 package.json 意味着他们的启动时间会比单独完成要慢,因为他们都需要安装包的所有依赖项,而不仅仅是他们自己的
      • 如果 index.js 中有多个导出函数,例如 hi()hello(),那么 hi 云函数也会将 hello() 函数加载到内存中,尽管不使用它,并且 hello 云函数也会有 hi() 在内存中,尽管没有使用它,因为生成的云函数仍将使用相同的 index.js 文件,即使其他部分没有,也会将该模块内的所有内容加载到内存中不需要
      • say even if the modules one.js and two.js require different packages at runtime, the shared package.json between them means that their startup time will be slower than if done individually as they will both need to install all the dependencies of the package rather than just their own
      • if you have several exported functions inside index.js, such as hi() and hello(), then the hi cloud function will also have the hello() function loaded in memory despite not using it, as well as the hello cloud function will have hi() in memory despite not using it, as for both the resulting cloud function will still use the same index.js file, loading everything inside that module into memory even if other parts aren't needed

      因此,确保您的云功能以尽可能少的运行时占用空间以最佳方式运行的最佳做法是什么?Google 的设计决策似乎意味着您制作的云功能越多,每个云功能捆绑的垃圾就越多,从而减慢它们的速度并增加成本.

      As such, what is the best practice for making sure your cloud functions run optimally with the lightest runtime footprint possible? As it seems the design decisions by Google mean that the more cloud functions you make, then the more junk gets bundled with each cloud function, slowing them down and costing more.

      另一方面,在我看来,这对 google 来说是一个更好的方法:每个云函数都应该有自己的目录,并且在每个目录中都有一个 package.json 文件和index.js 文件.index.js 文件然后执行 module.exports = function(...args){}export default function(...args){}.

      As an side, it seems to me that this would have been a better approach for google: Each cloud function should have its own directory, and in each directory there is a package.json file and a index.js file. The index.js file then does a module.exports = function(...args){} or a export default function(...args){}.

      通过这种方式,架构与人们期望云函数的运行方式保持一致——因为云函数代表单个函数——而不是云函数是在所有云函数之间安装共享依赖项,然后加载一个可以包含多个云功能但只使用一个的模块,然后只执行该加载模块中的一个功能.

      This way the architecture aligns with how one expects cloud functions to operate - being that a cloud function represents a single function - rather than a cloud function being the installation of the shared dependencies between your all your cloud functions, then the loading of a module that can contain multiple cloud functions but only one is used, then the execution of only one function out of that loaded module.

      有趣的是,Azure Functions 的设计似乎与我期望的云函数运行方式完全一致:https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node

      Funnily enough, Azure Functions seems be designed exactly the way I expect cloud functions to operate: https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node

      推荐答案

      与其单独导出每个云函数,我们可以通过要求导出特定目录及其子目录中的每个文件的文件来一次导出所有函数.

      Rather than exporting each Cloud Function individually, we can export all of them at once by requiring a file that export's every file in a specific directory and its subdirectories.

      'use strict';
      
      const admin = require('firebase-admin');
      const functions = require('firebase-functions');
      const logging = require('@google-cloud/logging')();
      const stripe = require('stripe')(functions.config().stripe.token);
      
      admin.initializeApp(functions.config().firebase);
      
      module.exports = require('./exports')({
          admin, functions, logging, stripe
      });
      

      我们可以为每个提供者创建一个文件夹,例如auth, database, https,我们可以在其中组织相关资源的事件,例如auth.user.onCreatedatabase.ref.onWrite.

      We can create a folder for each provider, e.g. auth, database, https, in which we can organise the associated resource's events such as auth.user.onCreate or database.ref.onWrite.

      通过在每个文件中使用事件以这种方式构建我们的文件,我们可以搜索函数文件并使用文件路径动态创建云函数的名称并将其导出.

      By structuring our files this way with an event in each file, we can search for the function files and use the file path to dynamically create the Cloud Function's name and export it.

      例如functions/exports/auth/user/onCreate.f.js ->onCreateAuthUser

      'use strict';
      
      module.exports = (app) => {
      
          const glob = require('glob');
      
          glob.sync('./**/*.f.js', { cwd: __dirname }).forEach(file => {
      
              const only = process.env.FUNCTION_NAME;
              const name = concoctFunctionName(file);
      
              if (only === undefined || only === name) {
                  exports[name] = require(file)(app);
              }
          });
      
          return exports;
      }
      
      function concoctFunctionName(file) {
      
          const camel = require('camelcase');
          const split = file.split('/');
          const event = split.pop().split('.')[0];
          const snake = `${event}_${split.join('_')}`;
      
          return camel(snake);
      }
      

      最后,我们的函数文件可以使用传递的参数来访问常用的服务,例如 Firebase Admin 和 Functions,甚至 Stripe.

      Finally, our function files can use the argument passed to access commonly required services such as Firebase Admin and Functions, and even Stripe.

      'use strict';
      
      module.exports = ({ admin, functions, stripe }) => {
      
          return functions.auth.user().onCreate(event => {
      
              const { email, uid } = event.data;
              const ref = admin.database.ref.child(`user-customer/${uid}`);
      
              return stripe.customers.create({ 
                  email, metadata: { uid } 
              }).then(customer => {
                  return ref.set(customer);
              });
          });
      }
      

      这篇关于创建多个轻量级 Google Cloud Functions 的最佳实践?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆