-
-
Notifications
You must be signed in to change notification settings - Fork 142
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Memory usage grows exponentially of the esbuild process #98
Comments
I can confrim this. I am running into |
From what I can see this does the leak: serverless-esbuild/src/index.ts Line 160 in ad3e93e
true option here is using incremental bundling. Maybe a lead.
|
incremental build does keep things in memory to speed up subsequent bundling: https://esbuild.github.io/api/#incremental. Could it be a leak in esbuild itself? Should we call Or we could leave the watching to esbuild itself : https://esbuild.github.io/api/#watch, and see if memory is better handled but I guess this was sub-optimal @floydspace ? |
@olup I think it's just used incorrectly. We need to call |
Yes true, otherwise the cache is a bit lost anyway. I'll flesh a pr tomorrow. Beyond this one subject, serverless offline, in watch mode, is terribly leaking so the rest of the process will end up eating the whole memory anyway. But we can improve what depends on us. |
I rewrote it to use rebuild. Sadly this does not resolve the memory issue. #101 so I think it might actually be an esbuild issue. But I am unable to verify it with:
|
I am reporting I've had similar issues, each build just linearly increases the amount of memory esbuild is using (about 2.5GB per file change, it pretty quickly gets up to 20GB), if I was to hazard a guess, I'm thinking it has something to do with
I have a feeling something is causing all the metadata change from ESBuilds perspective and it might not garbage collect old metadata (I imagine it doesn't watch for that). But I haven't looked at any of the code for
I'd be curious what this responds back with when logging is set to max I might experiment a little tonight with this |
I've been experiencing the same problem of exponential growth in memory usage. As far as I can tell, With the changes in my PR, memory usage seems to cap out around 1 GB (for my current codebase), whereas it used to increase exponentially until crashing. Let me know if the PR #123 solves your problem @olup or @thomaschaaf. |
That PR partially fixed the issue for me (it still uses a lot of memory, but not as much), but The problem of enabling I put in a very blunt workaround in the compiled
This patched version + using Not sure if serverless-offline has an "official" way of bundlers to manage cache... |
Indeed, I put the link somewhere, but the memory leak in serverless offline is well known and affecting everyone, and the relation with the caching option is discussed around, but the accepted answer seems to be "that's how it is". So no official way to fix this. A workaround in our codebase would be a very good idea, as the memory leak is a real pain, thanks a lot for sharing this ! Only we should probably put it behind some options and disabled by default, and document it. |
Before a more official solution is in place, this is what we ended up using: # serverless.yml
custom:
serverless-offline:
allowCache: true # Important: This will prevent serverless-offline from eating all of your memory
# ...
esbuild:
plugins : ./esbuild/plugins.js
# .... // esbuild/plugins.js
let refreshServer = {
name: "refresh-server",
setup(build) {
build.onEnd((result) => {
if (build.initialOptions.incremental) {
console.log(`refresh-server: Clearing Cache for ${build.initialOptions.entryPoints.join(", ")}...`);
// Remove all items from the cache (this will force node to reload all of the built artifacts)
Object.keys(require.cache).forEach(function (key) {
const resolvedPath = require.resolve(key);
if (resolvedPath.includes(build.initialOptions.outdir)) {
delete require.cache[key];
}
});
}
});
},
};
module.exports = [refreshServer]; By utilising the esbuild plugin system we just did the clearing there instead of in the Hope that helps someone else... |
Brilliant ! And it's much better than having inside the lib, indeed. |
Only small problem is the esbuild plugins don't get any serverless context, I'll continue playing around with this and see if I find any issues regarding that. EDIT: Already ran into an issue with this if it's running during I made a few changes to the plugin to be much more selective instead of clearing out everything, it should only clear out entries in the esbuild output directory. |
@mattisdada your solution seems to work for use with |
In addition to ameliorating memory eating-issues, I was also having issues where hot reloading wasn't working for me, and the solution from @mattisdada also fixed that. Thank you! |
@mattisdada I'm trying to implement your solution on a TypeScript project with around 8 functions, but I'm getting a weird issue, after running
Any idea why this could be happening? |
Hmm, it's a pretty simple and dumb plugin, so I have to guess the events is being mangled somehow, none of the actions it's doing should be triggering a new esbuild build. Out of curiosity when it is removed (but nothing else has been changed) does the infinite loop still occur? I have to guess it's a file system related issue (esbuild is generating something that is then being picked up by esbuild, and repeats; or something similiar) I'm also not sure why this was added, I can only expect it to break things 🤔 :
|
When the plugin is removed, and after a single save the memory usage keeps incrementing, I have stopped the process when it reaches to 14 GB or so. I removed the line you mentioned |
I think you've got something else going wrong that's triggering the builds to re-trigger unrelated to the plugin: Try just logging that esbuild build is being triggered: // esbuild/plugins.js
let refreshServer = {
name: "refresh-server",
setup(build) {
build.onEnd((result) => {
if (build.initialOptions.incremental) {
console.log(`refresh-server: Clearing Cache for ${build.initialOptions.entryPoints.join(", ")}...`);
}
});
},
};
module.exports = [refreshServer]; Do you have anything that would be writing to your src directory? And what other plugins do you have installed? |
I don't think there is anything writing to the src dir. We have the following plugins: serverless-esbuild, serverless-offline, serverless-openapi-documentation-v2 and serverless-hooks. This is a small sample of the logs (the plugin is just logging):
The ram usage never stops incrementing. |
The revised plugin only does logging, and does nothing else, your problem is outside the plugin. I recommend copying the project elsewhere and just keep removing things until it works as expected. (plugins, functions, config, etc) I suspect Once you've discovered the source, modify the watch |
Thank very much for the guidance, I'll look into it and get back with the fix. |
In my cause I had the same issue before I refactored packages import. When I have import like this: |
@mrjavi91 Did you ever find a fix? I'm having the exact same issue |
@SamPF53 No, I haven't found a fix yet. I tried what @svoitovych0218 suggested, with no luck. Did you try that too? Please let me know if that works for you or not. |
@mrjavi91 - I just upgraded to the latest esbuild (0.15.5) and latest serverless-esbuild (1.32.8) and am not getting the endless loop anymore! Hopefully that resolves it for you. I was having an issue with hot reloading as well, but realized the handler was never reloading. Note for anyone having issues with hot reloading to set the "scripts": {
"local": "set NODE_OPTIONS=\"--enable-source-maps\"&& serverless offline --stage local --reloadHandler", |
Anyone still experiencing this with Node20 or Node21? I'm using this pattern which seems to cause the memory to grow until it runs the executor out of resources. Removing the plugins does prevent the memory issue but I bump into other problems with the build regarding node internals and external dependencies. |
We are also experiencing this issue on mac os with apple chips, not seeing on the intel based mac |
I have this on Intel based Mac |
Follow up to my post above, we found our issue to be a layer was not excluded in serverless.ts for esbuild. Once we added it to exclude list, the issue got resolved for us. |
this SEEM to work for me, thank you so much <3 |
When using serverless-offline and making changes to files the memory usage of the esbuild process seems to grow exponentially.
I start out with about 1 GB of ram usage and after 10 changes the esbuild process is using 8 GB of ram.
The text was updated successfully, but these errors were encountered: