通过无服务器框架部署到 AWS Lambda 时,将文件打包到应用程序包的特定文件夹中

nbu*_*urk 3 aws-lambda serverless-framework serverless prisma

语境

\n

我正在使用无服务器框架aws-node-typescript的示例。我的目标是将Prisma集成到其中。

\n

到目前为止,我有:

\n
    \n
  1. 使用本地创建项目serverless create
  2. \n
  3. 在 Railway 上设置 PostgreSQL 数据库
  4. \n
  5. 安装prisma、运行prisma init、创建基本模型并成功User运行prisma migrate dev
  6. \n
  7. users通过复制现有hello函数创建第二个函数
  8. \n
  9. 使用部署该功能serverless deploy
  10. \n
  11. 现在在我的函数中,当我实例化 时PrismaClient,我收到内部服务器错误,并且该函数记录此错误:"ENOENT: no such file or directory, open \'/var/task/src/functions/users/schema.prisma\'"
  12. \n
\n

我的项目结构如下:

\n
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 README.md\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 package-lock.json\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 package.json\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 prisma\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 migrations\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 20221006113352_init\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 migration.sql\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 migration_lock.toml\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 schema.prisma\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 serverless.ts\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 functions\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 hello\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 handler.ts\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 index.ts\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 mock.json\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 schema.ts\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 index.ts\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 users\n\xe2\x94\x82   \xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 handler.ts\n\xe2\x94\x82   \xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 index.ts\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 libs\n\xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 api-gateway.ts\n\xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 handler-resolver.ts\n\xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 lambda.ts\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 tsconfig.json\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 tsconfig.paths.json\n
Run Code Online (Sandbox Code Playgroud)\n

另外,这是该函数的处理程序users:\nts

\n
import { formatJSONResponse } from \'@libs/api-gateway\';\nimport { middyfy } from \'@libs/lambda\';\nimport { PrismaClient } from \'@prisma/client\'\n\nconst users = async (event) => {\n\n  console.log(`Instantiating PrismaClient inside handler ...`)\n  const prisma = new PrismaClient()\n\n  return formatJSONResponse({\n    message: `Hello, ${event.queryStringParameters.name || \'there\'} welcome to the exciting Serverless world!`,\n    event,\n  });\n};\n\nexport const main = middyfy(users);\n
Run Code Online (Sandbox Code Playgroud)\n

出现问题的原因是为了实例化PrismaClient,该schema.prisma文件需要成为应用程序包的一部分。具体来说,它需要在/var/task/src/functions/users/如错误消息所示。

\n

我已经将文件package.patterns中的选项调整serverless.ts为如下所示:

\n
package: { individually: true, patterns: ["**/*.prisma"] },\n
Run Code Online (Sandbox Code Playgroud)\n

问题

\n

这样,上传到 AWS Lambda 的包prisma在其根目录中包含该目录,这是.serverless我运行后的文件夹sls package(我已users.zip在此处解压缩,以便您可以看到其内容):

\n
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 cloudformation-template-create-stack.json\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 cloudformation-template-update-stack.json\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 hello.zip\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 serverless-state.json\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 users\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 prisma\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 schema.prisma\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 functions\n\xe2\x94\x82           \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 users\n\xe2\x94\x82               \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 handler.js\n\xe2\x94\x82               \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 handler.js.map\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 users.zip\n
Run Code Online (Sandbox Code Playgroud)\n

我还可以确认我的 AWS Lambda 的部署版本具有相同的文件夹结构。

\n

我怎样才能将users/prisma/schema.prisma文件移动到users/src/functions/userspatternsserverless.ts

\n

nbu*_*urk 5

我找到了一个(相当丑陋的)解决方案。如果有人能想到一个更优雅的方法,我仍然对此持开放态度,并很乐意为您提供正确答案的分数。

\n

解决"ENOENT: no such file or directory, open \'/var/task/src/functions/users/schema.prisma\'"错误

\n

为了解决这个问题,我只是采取了一种非常幼稚的方法,手动将文件从目录复制到. 这是我现在的文件结构:schema.prismaprismasrc/functions/users

\n
.\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 README.md\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 package-lock.json\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 package.json\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 prisma\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 migrations\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 20221006113352_init\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 migration.sql\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 migration_lock.toml\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 schema.prisma\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 serverless.ts\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 src\n\xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 functions\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 hello\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 handler.ts\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 index.ts\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 mock.json\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 schema.ts\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 index.ts\n\xe2\x94\x82   \xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 users\n\xe2\x94\x82   \xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 schema.prisma\n\xe2\x94\x82   \xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 handler.ts\n\xe2\x94\x82   \xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 index.ts\n\xe2\x94\x82   \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 libs\n\xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 api-gateway.ts\n\xe2\x94\x82       \xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 handler-resolver.ts\n\xe2\x94\x82       \xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 lambda.ts\n\xe2\x94\x9c\xe2\x94\x80\xe2\x94\x80 tsconfig.json\n\xe2\x94\x94\xe2\x94\x80\xe2\x94\x80 tsconfig.paths.json\n
Run Code Online (Sandbox Code Playgroud)\n

这显然是解决此问题的一种可怕方法,因为我现在在不同位置有两个 Prisma 架构文件,并且必须确保在src/functions/users/schema.prisma更改原始文件后始终更新其中的prisma/schema.prisma文件以保持它们同步。

\n

当我复制该文件并重新部署后,该schema.prisma文件就位于 AWS Lambda 中的正确位置,并且错误消失并且PrismaClient可以实例化。

\n

然后我在处理程序中添加了一个简单的 Prisma 客户端查询:

\n
const users = async (event) => {\n  console.log(`Instantiating PrismaClient inside handler ...`)\n  const prisma = new PrismaClient()\n\n  const userCount = await prisma.user.count()\n  console.log(`There are ${userCount} users in the database`)\n  return formatJSONResponse({\n    message: `Hello, ${event.queryStringParameters.name || \'there\'} welcome to the exciting Serverless world!`,\n    event,\n  });\n};\n\nexport const main = middyfy(users);\n
Run Code Online (Sandbox Code Playgroud)\n

...并遇到了一个新的错误,这次是关于查询引擎的:

\n
Invalid `prisma.user.count()` invocation:\n\n\nQuery engine library for current platform \\"rhel-openssl-1.0.x\\" could not be found.\nYou incorrectly pinned it to rhel-openssl-1.0.x\n\nThis probably happens, because you built Prisma Client on a different platform.\n(Prisma Client looked in \\"/var/task/src/functions/users/libquery_engine-rhel-openssl-1.0.x.so.node\\")\n\nSearched Locations:\n\n  /var/task/.prisma/client\n  /Users/nikolasburk/prisma/talks/2022/serverless-conf-berlin/aws-node-typescript/node_modules/@prisma/client\n  /var/task/src/functions\n  /var/task/src/functions/users\n  /var/task/prisma\n  /tmp/prisma-engines\n  /var/task/src/functions/users\n  \n  \n  To solve this problem, add the platform \\"rhel-openssl-1.0.x\\" to the \\"binaryTargets\\" attribute in the \\"generator\\" block in the \\"schema.prisma\\" file:\ngenerator client {\n  provider      = \\"prisma-client-js\\"\n  binaryTargets = [\\"native\\"]\n  }\n\nThen run \\"prisma generate\\" for your changes to take effect.\nRead more about deploying Prisma Client: https://pris.ly/d/client-generator\n
Run Code Online (Sandbox Code Playgroud)\n

解决Query engine library for current platform \\"rhel-openssl-1.0.x\\" could not be found.错误

\n

我对 Prisma 非常熟悉,知道 Prisma Client 依赖于一个查询引擎二进制文件,该二进制文件必须专门为 Prisma Client 将运行的平台构建。这可以通过我的 Prisma 模式中的块binaryTargets上的字段进行配置generator。AWS Lambda 的目标是rhel-openssl-1.0.x.

\n

所以我schema.prisma相应地调整了文件(在两个位置):

\n
generator client {\n  provider = "prisma-client-js"\n  binaryTargets = ["native", "rhel-openssl-1.0.x"]\n}\n
Run Code Online (Sandbox Code Playgroud)\n

之后,我跑去npx prisma generate更新生成的Prisma Client node_modules

\n

然而,这还没有解决错误,问题仍然是 Prisma 客户端找不到查询引擎二进制文件。

\n

schema.prisma因此,当文件丢失时,我采用了相同的方法:

\n
    \n
  1. 我手动将其复制到src/functions/users(这次是从其内部位置node_modules/.prisma/libquery_engine-rhel-openssl-1.0.x.so.node
  2. \n
  3. package.patterns我在我的serverless.ts:\n中添加了该属性的新路径
    package: { \n  individually: true, \n  patterns: ["**/*.prisma", "**/libquery_engine-rhel-openssl-1.0.x.so.node"],\n},\n
    Run Code Online (Sandbox Code Playgroud)\n
  4. \n
\n

当我重新部署并测试该功能后,又出现了一个错误:

\n
Invalid `prisma.user.count()` invocation:\n\n\nerror: Environment variable not found: DATABASE_URL.\n-->  schema.prisma:11\n| \n10 |   provider = \\"postgresql\\"\n11 |   url      = env(\\"DATABASE_URL\\")\n| \n\nValidation Error Count: 1\n
Run Code Online (Sandbox Code Playgroud)\n

解决Environment variable not found: DATABASE_URL.错误

\n

这次,非常简单,我进入 AWS 控制台并通过控制台 UIhttps://us-east-1.console.aws.amazon.com/lambda/home?region=us-east-1#/functions/aws-node-typescript-dev-users?tab=configure添加了一个DATABASE_URL环境变量,指向 Railway 上的 Postgres 实例:

\n

在此输入图像描述

\n