Google Cloud Functions的工作方式是:
functions
目录functions
目录包含一个package.json
文件,用于包含所有模块的共享依赖项firebase-functions
的侦听器方法返回处理程序,但也将触发器元数据附加到该处理程序。然后firebase-tools
cli应用程序在本地需要您的代码,获取导出的函数,然后根据其来自firebase函数内容的附加元数据为每个导出的方法创建云函数。因此,如果您将所有云功能放在同一个模块中,那么它将为每个云功能多次部署该模块,并为每个云功能加载整个模块,然后调用特定的导出功能。 这很奇怪:
one.js
和two.js
在运行时需要不同的包,它们之间的共享package.json
意味着它们的启动时间比单独完成时要慢,因为它们都是需要安装包的所有依赖项而不仅仅是自己的index.js
中有多个导出的函数,例如hi()
和hello()
,那么hi
云函数也会加载hello()
函数尽管没有使用它,但在内存中尽管没有使用它,hello
云函数也会在内存中hi()
,因为生成的云函数仍将使用相同的index.js
文件,即使不需要其他部分,也要将该模块内的所有内容加载到内存中因此,确保云功能以最轻的运行时足迹运行的最佳实践是什么?由于Google的设计决策似乎意味着您制作的云功能越多,因此每个云功能捆绑的垃圾越多,速度越慢,成本越高。
作为一方,在我看来,这对谷歌来说是一个更好的方法:每个云功能都应该有自己的目录,并且在每个目录中都有一个package.json
文件和一个{{1}文件。然后index.js文件执行index.js
或module.exports = function(...args){}
。
这种架构符合人们期望云功能运行的方式 - 云功能代表单一功能 - 而不是云功能是在所有云功能之间安装共享依赖关系,然后加载一个可以包含多个云函数但只使用一个的模块,然后只从该加载的模块中执行一个函数。
有趣的是,Azure功能似乎的设计与我希望云功能运行的方式完全相同:https://docs.microsoft.com/en-us/azure/azure-functions/functions-reference-node
答案 0 :(得分:4)
我们可以通过要求导出特定目录及其子目录中的每个文件的文件,而不是单独导出每个云功能,而不是一次导出所有这些功能。
功能/ index.js'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,数据库,https,我们可以在其中组织相关资源的事件,例如auth.user.onCreate
或database.ref.onWrite
。
通过在每个文件中使用事件构建我们的文件,我们可以搜索函数文件并使用文件路径动态创建Cloud Function的名称并将其导出。
e.g。 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管理和函数,甚至Stripe。
功能/出口/认证/用户/ onCreate.f.js'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);
});
});
}
答案 1 :(得分:1)
我正在使用modofun(https://modofun.js.org),这是一个基于请求路径的多个操作的路由器。这允许我将相关功能收集到一个部署为单个Google Cloud Function的模块中。该模块中所有函数的依赖关系是相同的,因此使其具有依赖性。您还可以共享共同的全局资源,例如数据库连接。
我同意单独部署每一项功能都是浪费资源,而且很难维护。
我为生产中的Google Cloud Functions部署做了这个。