为什么调试会在使用 "sam invoke local" 时中断对 AWS::Lamba::LayerVersion 的访问?

Why does debugging break access to an AWS::Lamba::LayerVersion when using "sam invoke local"?

这个有效:

sam local invoke -t template.local.yaml -e events/event-timezone.json GetTimezoneFunction

尝试使用 Visual Studio 代码进行调试时,这不起作用:

sam local invoke -t template.local.yaml -e events/event-timezone.json -d 5858 GetTimezoneFunction

不同之处在于,在第二个中,我收到一个错误消息,即未找到在我的 lambda 函数使用的单独层中定义的 npm 'axios' 模块。

Error: Cannot find module 'axios'
Require stack:
 - /var/task/get-timezone.js
 - /var/runtime/UserFunction.js
 - /var/runtime/index.js

我能想到的是,也许通过尝试使用调试器,层的资源没有复制到 Docker 运行时环境,或者某些文件搜索路径被破坏。

我有另一个 lambda 函数,它不需要层中的任何东西,无论有没有调试器都可以正常工作。

带有getTimeZone函数的文件开头为:

import axios from 'axios';

这是template.local.yaml的相关部分:

AWSTemplateFormatVersion: '2010-09-09'
Transform: AWS::Serverless-2016-10-31
Description: AWS Sample

Globals:
  Function:
    Timeout: 30

Resources:
  SampleCommonLayer:
    Type: AWS::Lambda::LayerVersion
    Properties:
      CompatibleRuntimes:
        - nodejs12.x
      Content: dependencies
      Description: Sample Common LayerVersion
      LayerName: SampleCommonLayer

  GetTimezoneFunction:
    Type: AWS::Serverless::Function
    Properties:
      CodeUri: dist/get-timezone
      Handler: get-timezone.getTimezone
      Runtime: nodejs12.x
      Layers:
        - !Ref SampleCommonLayer
      Events:
        GetTimezone:
          Type: Api
          Properties:
            Path: /get-timezone
            Method: get

Outputs:
  GetTimezoneApi:
    Description: "API Gateway endpoint URL for Prod stage for getTimezone function"
    Value: !Sub "https://${ServerlessRestApi}.execute-api.${AWS::Region}.amazonaws.com/Prod/get-timezone/"
  GetTimezoneFunction:
    Description: "getTimezone Lambda Function ARN"
    Value: !GetAtt GetTimezoneFunction.Arn
  GetTimezoneFunctionIamRole:
    Description: "Implicit IAM Role created for getTimezone function"
    Value: !GetAtt GetTimezoneFunctionRole.Arn

这是我的 launch.json:

{
  "version": "0.2.0",
  "configurations": [{
      "name": "Debug get-timezone",
      "type": "node",
      "request": "attach",
      "address": "localhost",
      "port": 5858,
      "localRoot": "${workspaceRoot}/dist",
      "remoteRoot": "/var/task",
      "protocol": "inspector",
      "stopOnEntry": false,
      "preLaunchTask": "local-tz-debug"
    },
    ...
  ]
}

到目前为止,我在寻找这个问题的答案时只发现了很多未解决的问题和一些不完全相同的问题。

我让我的一个 lambda 函数转储了 process.env 中的所有环境变量,并发现启用调试(通过 -d 5858)和未启用调试之间存在一些差异,大多数值得注意的是,启用调试时未定义 NODE_PATH

我想我曾经尝试修复 NODE_PATH 一次,基于我在其他地方读到的类似问题,但它似乎没有帮助。

现在我正在转储环境变量,但是,我可以看到我在 env.json 文件中定义 NODE_PATH 的尝试没有任何效果。那时我发现 SAM 忽略了任何未在我的模板中明确定义的环境变量,无论是作为全局变量还是针对每个 lambda。

这解决了那个问题:

Globals:
  Function:
    Timeout: 30
    Environment:
      Variables:
        NODE_PATH: /opt/nodejs/node12/node_modules:/opt/nodejs/node_modules:/var/runtime/node_modules

一旦我解决了这个问题,然后它发现我需要调整我的 launch.json 以获得适用于 TypeScript 的调试器断点:

{
  "version": "0.2.0",
  "configurations": [{
      "name": "Debug get-timezone",
      "type": "node",
      "request": "attach",
      "address": "localhost",
      "port": 5858,
      "localRoot": "${workspaceRoot}/dist/get-timezone", // <- More specific path needed
      "remoteRoot": "/var/task",
      "protocol": "inspector",
      "stopOnEntry": false,
      "preLaunchTask": "local-tz-debug",
      "outFiles": [ // <- Added this
        "${workspaceRoot}/dist/get-timezone/**/*.js"
      ],
      "sourceMaps": true // <- Added this
    },
    ...
  ]
}

我只想为本地测试定义 NODE_PATH 变量,而不是为部署定义,所以我有一个单独的 template.yaml 文件,没有该定义用于部署。 template.yaml 还将 LayerVersionContent 定义为 nodejs.zip,而不是 dependencies。我从 template.yaml 自动生成 template.local.yaml,这样我就不必维护两个独立的几乎相同的模板。

我希望将来有更好的方法来做到这一点,但现在它已经完成了工作。