floydspace / serverless-esbuild

💨 A Serverless framework plugin to bundle JavaScript and TypeScript with extremely fast esbuild
MIT License
444 stars 136 forks source link

Hangs indefinitely on esbuild error #532

Open dhmw opened 4 months ago

dhmw commented 4 months ago

Describe the bug

It seems that if this plugin encounters any esbuild error, it will hang. This is particularly bad in a CI env where the stdout may not be flushed and the process is waiting for timeout and consuming billable build minutes.

To Reproduce

Introduce some issue which causes esbuild to fail.

When I run the deploy locally, I get the stdout flushed and can see what the issue is. But the process still hangs.

Deploying to $ACCOUNT_ID using service-foo-us-east-1-DeployerRole
Deploying service-foo to stage staging (us-east-1)
✘ [ERROR] Top-level await is not available in the configured target environment ("es2020")
    ../../libs/foo/dist/path/index.js:72:11:
      72 │     false: await calculateConfigs(false),
         ╵            ~~~~~
✖ Stack service-foo-staging failed to deploy (0s)
Environment: linux, node 20.11.0, framework 3.38.0 (local), plugin 7.2.0, SDK 4.5.1
Credentials: Local, environment variables
Docs:        docs.serverless.com
Support:     forum.serverless.com
Bugs:        github.com/serverless/serverless/issues
Error:
Error: Build failed with 2 errors:
../../libs/foo/dist/path/index.js:72:11: ERROR: Top-level await is not available in the configured target environment ("es2020")
../../libs/foo/dist/path/index.js:73:10: ERROR: Top-level await is not available in the configured target environment ("es2020")
    at failureErrorWithLog (/home/developer/our-monorepo/node_modules/esbuild/lib/main.js:1651:15)
    at /home/developer/our-monorepo/node_modules/esbuild/lib/main.js:1059:25
    at /home/developer/our-monorepo/node_modules/esbuild/lib/main.js:1004:52
    at buildResponseToResult (/home/developer/our-monorepo/node_modules/esbuild/lib/main.js:1057:7)
    at /home/developer/our-monorepo/node_modules/esbuild/lib/main.js:1069:9
    at new Promise (<anonymous>)
    at requestCallbacks.on-end (/home/developer/our-monorepo/node_modules/esbuild/lib/main.js:1068:54)
    at handleRequest (/home/developer/our-monorepo/node_modules/esbuild/lib/main.js:732:17)
    at handleIncomingPacket (/home/developer/our-monorepo/node_modules/esbuild/lib/main.js:757:7)
    at Socket.readFromStdout (/home/developer/our-monorepo/node_modules/esbuild/lib/main.js:680:7)
    at Socket.emit (node:events:518:28)
    at Socket.emit (node:domain:488:12)
    at addChunk (node:internal/streams/readable:559:12)
    at readableAddChunkPushByteMode (node:internal/streams/readable:510:3)
    at Readable.push (node:internal/streams/readable:390:5)
    at Pipe.onStreamRead (node:internal/stream_base_commons:190:23)

Expected behavior

I would expect this log to be flushed and the process to exit with non zero code.

Versions (please complete the following information):

quitedensepoint commented 2 months ago

For me, going back to 0.16.17 of esbuild avoids the hang. 0.17.0, the version immediately afterwards, triggers the hang. Here are the release notes for 0.17.0, in case anything sticks out: https://github.com/evanw/esbuild/releases/tag/v0.17.0

rluong-varicent commented 1 week ago

It's really weird because it "sometimes" fails depending on the type of esbuild error. When I try to reference a class incorrectly such as

file1.ts

export default temp class () {}

file2.ts

import { temp } from './file1';

This seems to hang (sometimes). I've had it where it was fully working another time.

However, if I do `import { temp2 } from './file1'; It seems to error differently? Which is quite strange because looking at where the code in the plugin breaks:

It breaks after before:package:createDeploymentArtifacts here: https://github.com/floydspace/serverless-esbuild/blob/master/src/index.ts#L154

Which is calling the bundleMapper from here: https://github.com/floydspace/serverless-esbuild/blob/master/src/bundle.ts#L137-L139

And it fails here in my case: https://github.com/floydspace/serverless-esbuild/blob/master/src/bundle.ts#L119

Now, here's what's weird to me. pMap handles the error well throws, it did not swallow the error.

I'm so confused because if I put a catch on the bundle invocation inside the createDeploymentArtifiacts and rethrow the error. It will STILL hang.

However, if I throw before the execution then it's fine. I've tried running why-is-node-running and it's still not entirely clear.

It has come to my attention that serverless framework v4 is actually in GA and uses esbuild natively? I'm going to see if it works with that.

small update

# PROCESSWRAP
node:internal/async_hooks:202                                                         
node:internal/child_process:264                                                       
/Users/.../projects/working/node_modules/esbuild/lib/main.js:1976              - let child = child_process.spawn(command, args.concat(`--service=${"0.23.0"}`, "--ping"), {
/Users/.../projects/working/node_modules/esbuild/lib/main.js:1875              - var context = (buildOptions) => ensureServiceIsRunning().context(buildOptions);
/Users/.../projects/working/node_modules/serverless-esbuild/dist/bundle.js:110 - const context = await pkg.context?.(options);
/Users/.../projects/working/node_modules/p-map/index.js:57                     - result[index] = await mapper(element, index);

something to do with esbuild (I know, I know) ... I'm going to check the values from both errors and see the difference. I'm going to see if I can boil it down to just using esbuild standalone. I think we'd probably want to find a way to kill the process. I mean I put a (process.exit(1)) to force kill it in these instances but I'm not sure that's ideal? maybe it is, regardless