serverless-esbuild icon indicating copy to clipboard operation
serverless-esbuild copied to clipboard

esbuild Process Using 13+ GB of Memory

Open cdalton713 opened this issue 3 years ago • 18 comments

Describe the bug The esbuild process is using a ridiculous amount of memory. Our backend stack is relatively small, less than two dozen endpoints.

To Reproduce

Serverless Config:

custom: {
...
    esbuild: {
      bundle: true,
      minify: false,
      sourcemap: true,
      incremental: true,
      exclude: ["aws-sdk", "pg-hstore"],
      target: "node16",
      define: { "require.resolve": undefined },
      platform: "node",
      concurrency: 5,
      // plugins: "./esbuild-plugin.js",
      packager: "pnpm",
      packagePath: "./package.json",
    },
    ...
}

Expected behavior Not 15 GB worth of memory for a build.

Screenshots or Logs CleanShot 2022-11-07 at 10 37 39@2x

Versions (please complete the following information):

  • OS: M1 Macbook 12.2.1
  • Serverless Framework Version: 3.24.0
  • Plugin Version: 0.15.10

cdalton713 avatar Nov 07 '22 17:11 cdalton713

I'm having the same issue, I try to run esbuild in CICD with limited ram capacity and the process is just growing exponentially to death of course. Can we force esbuild to run under a certain amount of ram for production build?

Hideman85 avatar Nov 15 '22 08:11 Hideman85

Setting concurrency = 1 and disableIncremental = true has worked as an interim fix; this reduced esbuid's memory usage to around 600 mb for us. However, these settings of course affect build times - local development is now becoming increasingly difficult because each rebuild takes so long to complete...

cdalton713 avatar Nov 15 '22 14:11 cdalton713

Oh thank you so much men, it saved me a lot of pain :+1: and actually in my side the speed is not that much impacted.

Hideman85 avatar Nov 17 '22 13:11 Hideman85

Thanks very much for the solution

mhamadyhya1 avatar Feb 12 '23 08:02 mhamadyhya1

I'm having this same problem, even after updating to latest. I've set concurrency to 1 but still have really high cpu and memory usage

esbuild.config.js

module.exports = () => ({
  // concurrency: os.availableParallelism(),
  concurrency: 2,
  target: ["node18"],
  sourcemap: true,
  sourcesContent: false,
  platform: "node",
  format: "cjs",
  loader: loaderMap,
  exclude: ["*"],
  packager: "yarn",
  keepNames: true,
  packagerOptions: {
    ignoreLockfile: true
  },
  watch: {
    pattern: ["./**/*.(js|ts|graphql|html)"],
    ignore: [".esbuild", "dist", "node_modules", ".build", "**/generated", "scripts"]
  }
});
image

The CPU will spike ot 500-800% while building and then calm down to 0 after it's done, but the memory stays high and climbs on each rebuild.

Versions (please complete the following information):

OS: M1 Macbook 13.5.2 Serverless Framework Version: 3.34.0 Plugin Version: 1.48.2


Edit After playing around with the source files and whatnot, I've determined that the memory grows with each function. In our case, we have 13 functions registered, which would give us ~13GB memory consumed by the esbuild process. When commenting out all but 1 function, it was only using 1GB. My guess is that it's bundling up the entire project for each function, and then just holding onto the memory through things like this.buildCache, this.buildResults, etc and not letting go of the memory for the entire lifespan of the EsbuildServerlessPlugin class


Edit the second: Realized that all my memory consumption was because esbuild was bundling node_modules locally. Adding

...(process.env.IS_OFFLINE === "true" && { packages: "external" })

fixed the memory hogging for me, but I still have issues with every time I save, the memory footprint increases

zack37 avatar Sep 20 '23 17:09 zack37

I believe I found the culprit. In the bundle.ts file, in the bundleMapper function, the "context" is getting created and returned, which I assume means that the context is not getting properly garbage collected.

I changed the code in the following ways (I just patched it);

  • I pulled the esbuild import out to the top-level rather than re-importing it every time.
  • I swapped out the context creation for a simple build command, and removed the context return.
-        const context = await pkg.context?.(options);
-        let result = await context?.rebuild();
-        if (!result) {
-            result = await pkg.build(options);
-        }
+        const result = await pkg.build?.(options);
...
-        return { bundlePath, entry, result, context };
+        return { bundlePath, entry, result };

This took my esbuild memory usage from ~16gb to ~200mb.

Joshuabaker2 avatar Oct 20 '23 18:10 Joshuabaker2

I was having the same problem, but even more dramatic (~80 Lambdas).

  1. Setting concurrency to 1 did not fix it.
  2. As a temporary workaround, deploying only the function code individually did work.
  3. Manually patching the way @Joshuabaker2 suggested does fix the issue for me and keeps the memory in much better shape.

How can we get this into the real implementation? I'd upvote.

juanito-caylent avatar Oct 27 '23 16:10 juanito-caylent

I'd hazard a guess that there are competing concerns here in that the context is being returned so serverless-offline works faster with incremental rebuilds (I didn't test this since serverless-offline was so slow for me that I wrote my own implementation to do local testing).

@juanito-caylent do you use serverless-offline with serverless-esbuild? If so, did the patch make a difference for that?

Joshuabaker2 avatar Oct 27 '23 17:10 Joshuabaker2

Seeing the same behaviour. My solution in the meantime was to do packaging without this plugin, and use a custom esbuild script, inspired by https://adieuadieu.medium.com/using-esbuild-in-your-serverless-framework-project-13723db5e32a.

It's not ideal, and I'll be glad to remove this if a solution is found

taijuten avatar Nov 14 '23 08:11 taijuten

@Joshuabaker2 which bundle.ts file are you referencing? is it https://github.com/floydspace/serverless-esbuild/blob/master/src/bundle.ts

Im still seeing some very high memory usage image

walterholohan avatar Nov 14 '23 09:11 walterholohan

@Joshuabaker2 which bundle.ts file are you referencing? is it https://github.com/floydspace/serverless-esbuild/blob/master/src/bundle.ts

Im still seeing some very high memory usage image

Yes that file @walterholohan , the return is on line 122.

@taijuten did you try removing the import and moving it top-level instead? Perhaps that is also needed.

Joshuabaker2 avatar Nov 14 '23 18:11 Joshuabaker2

Thanks @Joshuabaker2 , do you think we should raise a PR for this? As for large projects this can be a big issue when trying to run builds on CI especially if you are using cheap linux machines (such as Github actions ubuntu machines)

walterholohan avatar Nov 14 '23 22:11 walterholohan

I think it should be merged in, the confounding variable that I mentioned above would need some consideration though and since I don't actually use serverless-offline I'm not really in the position to evaluate it:

I'd hazard a guess that there are competing concerns here in that the context is being returned so serverless-offline works faster with incremental rebuilds (I didn't test this since serverless-offline was so slow for me that I wrote my own implementation to do local testing).

Joshuabaker2 avatar Nov 14 '23 22:11 Joshuabaker2

@floydspace what do you think?

walterholohan avatar Nov 14 '23 22:11 walterholohan

I'm seeing a similar issue here. I'm curious about what would prevent these changes from coming in?

MMMikeM avatar Jan 15 '24 10:01 MMMikeM

I'm on the same boat, experienced this problem a couple of times now, specially when making deploys with GitHub Actions and a moderate number of lambdas.

The GitHub Action runner just gets killed out of the blue, via external signal. No error happens in the action for it to be stopped, it just gets killed. I'm assuming the problem here is that the bundling process is taking more resources that the action runner has.

AlesioSinopoli avatar Feb 07 '24 12:02 AlesioSinopoli

consistent memory leak while bundling @aws-sdk v3

randomhash avatar Feb 08 '24 15:02 randomhash

I had the same problem, by removing all the import * as ...from my code I no longer had that problem

jeromeheissler avatar May 29 '24 09:05 jeromeheissler