aws-amplify / amplify-cli

The AWS Amplify CLI is a toolchain for simplifying serverless web and mobile development.
Apache License 2.0
2.81k stars 819 forks source link

VS Code breakpoints ignored during "amplify mock function" #13226

Open camiracle opened 3 years ago

camiracle commented 3 years ago

Before opening, please confirm:

How did you install the Amplify CLI?

npm

If applicable, what version of Node.js are you using?

14.15.5

Amplify CLI Version

4.45.2

What operating system are you using?

Windows 10

Amplify Categories

function

Amplify Commands

Not applicable

Describe the bug

I recently updated to the latest Amplify CLI, from version 4.17.2. Before the update, when I used amplify function invoke [functionName] from launch.json, I was able to set/hit break points in Visual Studio Code. Following the upgrade, when I run the debugger in VS Code using amplify mock function [functionName], breakpoints are ignored and the code runs to completion. I know the code is executing correctly because I'm seeing expected output written to the console.

I'm currently making use of this workaround from cjihrig: https://github.com/aws-amplify/amplify-cli/issues/1158#issuecomment-801195432

Expected behavior

When running amplify mock function in VS Code debugger, execution halts on breakpoints and allows interrogation of runtime variables, etc.

Reproduction steps

Log output

# Put your logs below this line

launch.json:

{
      "type": "node",
      "request": "launch",
      "name": "myFunction",
      "env": {
        "ENV": "mySandbox",
        "REGION": "my-region-9000",
      },
      "program": "someFolder/amplify",
      "args": [
        "mock",
        "function",
        "myFunction"
      ],
      "console": "integratedTerminal"
    },
nahuelpark commented 3 years ago

I don't know if it realted, but I have trouble with debug breakpoints when I use AppSync simulator when I try to break a GraphQL query/mutation that use a Direct Lambda Resolver. I found that this version changes in my yarn.lock file solve the issue:

imagen

It seems like amplify-function-plugin-interface@1.7.2 has some issue related.

Thank you.

two-pack commented 3 years ago

I have same probleam. I can debug a simple function on @aws-amplify/cli v4.43.0, but can't the same function in v4.44.0.

@nahuelpark wrote:

It seems like amplify-function-plugin-interface@1.7.2 has some issue related.

According to Release information, @aws-amplify/cli v4.44.0 included following change to amplify-function-plugin-interface.

may215 commented 2 years ago

This helped me to solve the issue: https://awstip.com/debugging-aws-lambda-functions-nodejs-based-using-vs-code-built-in-debugger-53d9d74ed9b7

oookoook commented 2 years ago

I'd been using the solution proposed by @cjihrig in https://github.com/aws-amplify/amplify-cli/issues/1158#issuecomment-800782576_

For Node.js lambda functions, you can use the inspector module in your code as a workaround:

require('inspector').open(9229, '127.0.0.1', true);
debugger;

This will start the debugger on port 9229 and wait for you to connect. You'll want to make sure:

  1. The mock run is started with a long enough timeout to give you time to you debug.
  2. This code is removed before shipping to a cloud environment.

This stopped working probably after upgrade to amplify-cli version 8. Now the amplify mock command doesn't use the Node installed in the system, but runs its custom runtime (supposedly to mimic the AWS Lambda environment as closely as possible) - you can see it in the example below, I have node 16 installed and mock uses node 14.

However, the Amplify-provided runtime does not offer the inspector module and throws and error:

PS C:\Users\Adam Kučera\dev\dnytra\dreamroi-recommender\amplify\backend\function\productupdater\test> node --version
v16.13.1
PS C:\Users\Adam Kučera\dev\dnytra\dreamroi-recommender\amplify\backend\function\productupdater\test> amplify mock function productupdater --event ./src/event.json --timeout 100
Ensuring latest function changes are built...
Starting execution...
Started!
Starting inspector... Waiting for debugger to attach on port 9229
v14.18.1
productupdater failed with the following error:
{
  stack: 'Error [ERR_INSPECTOR_NOT_AVAILABLE]: Inspector is not available\n' +
    '    at new NodeError (internal/errors.js:322:7)\n' +
    '    at inspector.js:25:9\n' +
    '    at NativeModule.compileForInternalLoader (internal/bootstrap/loaders.js:286:7)\n' +
    '    at NativeModule.compileForPublicLoader (internal/bootstrap/loaders.js:226:10)\n' +
    '    at loadNativeModule (internal/modules/cjs/helpers.js:40:9)\n' +
    '    at Function.Module._load (internal/modules/cjs/loader.js:772:15)\n' +
    '    at Module.require (internal/modules/cjs/loader.js:974:19)\n' +
    '    at Module.require (pkg/prelude/bootstrap.js:1719:31)\n' +
    '    at require (internal/modules/cjs/helpers.js:93:18)\n' +
    '    at initDebug (C:\\Users\\Adam Kučera\\dev\\dnytra\\dreamroi-recommender\\amplify\\backend\\function\\productupdater\\src\\index.js:48:9)',
  message: 'Inspector is not available',
  code: 'ERR_INSPECTOR_NOT_AVAILABLE'
}
Finished execution.

The code that throws the error:

console.log('Starting inspector... Waiting for debugger to attach on port 9229');
console.log(process.version);
require('inspector').open(9229, '127.0.0.1', true);
gailuron1964 commented 2 years ago

Is there any workaround with this ? Being able to debug the Amplify lambdas from my local machine (with pdb for Python or inspector for node) seems like a pretty strong requirement. How is this a P4 ???

Also, this is a regression, not a feature request. The inspector trick mentionned here: https://github.com/aws-amplify/amplify-cli/issues/1158#issuecomment-800782576

Was how I was able to do debugging in the past.

mstoyanovv commented 1 year ago

current workaround for me:

(async function(){ const response = await handler(event) console.log(response) })()

- add this config to your .vscode/launch.json file: 

{ "name": "Debug Amplify Function", "program": "${workspaceFolder}/.vscode/debug.js", "request": "launch", "skipFiles": ["/**"], "type": "pwa-node", "console": "externalTerminal", "env": { "AWS_REGION": "eu-west-1" } }


Be sure to add any env variables needed for the lambda to run under "env". Note: if lambda is using aws4 keys you either need to have aws profile set with them under '~/.aws/credentials/` and use '@aws-sdk/credential-provider-node' to get them or pass them as env variables which is not recommended due to security. (never commit aws4 keys to github!)
- Set a breaking point and run the debugger. 

It is nasty because handler and event are both hardcoded and need to be changed for diffferent scenarios but at least you can debug locally without console.log on each new line 🤣  
fakedob commented 1 year ago

Hello to everyone who are on this topic. It has been few years now, since we started using amplify as a backbone to our products and back in the time, there was a working solution on how to do REAL inline step debugging with VS Code. At the time, we had to develop a complex layer on top of our custom resolvers which wouldn't be possible without the ability to inspect the process internally. Ever since amplify cli changed the way it spawns the child process that call the resolver in the appropriate context, while running locally, I feel like I lost both of my hands. It has been a real pain to keep the dev performing the same as before. Finally, it has been two days, since I hit an impossible to trace issue in our code base, for which I desperately needed a way to inspect (in real scenario) the code, running on my machine with a debugger...

Following everything that I have read so far during the last two years, including the last 30 hours of non sleep, had finally resulted in the following 100% working solution to get the job done.

First, I had recently configured my localhost to point to local ip v6 address. It was the main reason, that I had to clone the entire amplify cli source and build it my self, so that reverse engineering it, I found out that there is lower communication layer for the dynamodb emulator, that cannot handle the ip v6 (hopefully yet!).

This was the moment that I finally figured out where does this package amplify-nodejs-function-runtime-provider comes from and where it goes to. Basically, this is the layer that receives the mocked context from the local dev server and instantiates a spawned process from the dev server, emulating a serverless way of cold starting our resolver.

It became clear, after inspecting closer this comment that even tough the code has changed, it should be possible to send --inspect argument to the spawned process, to which we could later attach with remote debugger. So:

  1. Remove your currently installed amplify cli from your global node modules.
  2. git clone https://github.com/aws-amplify/amplify-cli.git and optionally checkout your preferred version tag/branch
  3. cd amplify-cli&&yarn
  4. Edit amplify-cli/packages/amplify-nodejs-function-runtime-provider/src/utils/invoke.ts at line 6 as follows Screenshot 2023-04-19 at 21 32 22
  1. You can also add some basic logic, check env variable and change the parameters for example, just so you dont need to recompile the cli every time.
  2. So far, so good, run yarn setup-dev and leave it for few minutes. It will compile the whole cli. Keep in mind, if you make more changes, you must run yarn clean before running yarn setup-dev again.
  3. Create two files in your local .vsconfig folder as follows
    
    // launch.json

{ "version": "0.2.0", "configurations": [ { "name": "Amplify", "type": "node", "request": "attach", "port": 9229, "timeout": 0, "restart": true, "continueOnAttach": true, "preLaunchTask": "runAmplifyHost", "postDebugTask": "stopAmplifyHost" }, ], }

// tasks.json

{ "version": "2.0.0", "tasks": [ { "type": "shell", "label": "runAmplifyHost", "command": "node", "args": ["/amplify-cli/packages/amplify-cli/bin/amplify", "mock", "api", "--timeout", "30"], "problemMatcher": { "pattern": { "regexp": "" }, "background": { "activeOnStart": true, "beginsPattern": "^.GraphQL schema compiled successfully.", "endsPattern": "^.AppSync Mock endpoint is running at." } }, "isBackground": true, }, { "label": "stopAmplifyHost", "command": "echo ${input:terminate}", "type": "shell", } ], "inputs": [ { "id": "terminate", "type": "command", "command": "workbench.action.tasks.terminate", "args": "terminateAll" } ] }



* in the ```tasks.json``` file, replace the command place holder with the path of your cli build

* Keep in mind, placing a breakpoint will stay grey, because the file is not in the memory. Once you call your endpoint, it will load the file and spawn it in a process, this will open a debug session, while VS Code is trying to connect to it and your breakpoints will become red. Once the resolver is complete, you breakpoints will become grey again.

Hope it helps you as well :)
Ninjef commented 1 year ago

@fakedob Looks like you worked really hard to get that solution. But it appears to require monkey patching amplify and implementing a non-standard setup, which can cause all sorts of problems down the line.

I think we need the amplify CLI to support this natively instead so I'm adding my voice to this issue. Step-through debugging greatly increases development speed compared to using console.log on everything. Here's hoping the amplify devs can raise the priority of this!