-
Notifications
You must be signed in to change notification settings - Fork 580
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
Bundling for Lambda requires unnecessary dependencies #5516
Comments
When I replaced the compiled version of this file with the contents below in my minified bundle, the sso code treeshook out and I saw a 41KB reduction in bundle size and a 39 ms reduction in cold start time: import { fromEnv } from '@aws-sdk/credential-provider-env';
import {
chain,
CredentialsProviderError,
memoize,
} from '@smithy/property-provider';
export const defaultProvider = (init = {}) =>
memoize(
chain(...[fromEnv()], async () => {
throw new CredentialsProviderError(
'Could not load credentials from any providers',
false
);
}),
(credentials) =>
credentials.expiration !== undefined &&
credentials.expiration.getTime() - Date.now() < 300000,
(credentials) => credentials.expiration !== undefined
); The impact to coldstart is even greater if I use the sdk which is included on disk by the Lambda runtime. I have done a test where I minified everything but used what was on disk for You can see how I benchmarked and repeat it yourself using this repo. |
Hi @perpil , Thanks for the reproduction. I can confirm the observed behavior. I'll discuss it with the team and get back to you. All the best, |
Hi @perpil , After discussing this with the team I got some more context about this. We provide the entire credential provider chain so that the SDK code deployed can be platform agnostic, whether it runs on EC2, Lambda, EKS etc, it should just work. Since the bundling process happens prior to the deployment part, the bundler cannot know which platform its bundling for and so omitting the unnecessary providers is not possible. You can probably use something like Yarn Patch, but I cannot officially recommend it. Regarding this part
Using the SDK provided by lambda is going to be less optimized because it fits an even greater array of use cases. Cold start times are in fact lower when bundling and minifying as shown in our own benchmarking. Currently there is no way / plan to fix this. All the best, |
Hi @RanVaknin I understand the general purpose nature of the provider and the fact that bundling is not aware of the target platform. I am also aware that I can patch the provider myself and am successfully doing so using patch-package. The key point is that this is slowing down coldstarts for a large cross section of users (everyone using the V3 SDK and Lambda). The Lambda team would need to take incredible engineering effort to reduce coldstarts by 39 ms whereas making a change to the SDK comes at a much lower cost. There are multiple ways of solving this without breaking support for other platforms and maintaining backwards compatibility.
Any of these options would be better than what we have. I encourage you to reach out to former Lambda principal David Yanacek or current principal Nik Pinski before making a final decision. I spoke to both of them at re:invent and they understand the positives that reducing the cold start for everyone would have. It may seem small for the SDK team, but would be a big win for the Lambda team. |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread. |
@perpil in https://github.com/aws/aws-sdk-js-v3/releases/tag/v3.499.0, we released dynamic imports (lazy loading) for the node credential chain providers. SSO and other credential providers including their dependency clients will not be loaded if you resolve to ENV credentials or otherwise pass credentials directly to a client. If you use Webpack for Node.js apps with the SDK, these dynamic imports will be split into other chunks and not loaded unless necessary. At this time it is not available on AWS Lambda unless you bundle in or upload the |
Thanks for the update. I'm using esbuild and bundling. I modified my repro to use 3.499 so you can see the behavior yourself. I'm expecting the delta between me hand patching the defaultProvider to only include
I don't think this is currently true. As an experiment I tried setting both
Yep understood I'm bundling it. |
I've tracked down what is still loading the SSO client. It's The way to see this in my repro is: When you look in the logs, you'll see an Init Duration of >400ms. To remove the SSO impact:
You'll see an Init Duration closer to ~200ms. Rule of thumb, if you see an Init Duration >400 ms it's loading SSO, if it's closer to 200 it isn't. By making the SSO packages external, they are loaded from disk so the latency hit is very apparent in the Init Duration logs. |
We can check what is loaded by logging the require.cache. We have additional updates pending to defer both the providers and the underlying clients used by providers, such as SSO, STS, SSO OIDC. |
#5681 contains a second phase of implementing deferred loading. |
Just tested with 3.502. Init Duration is on par with the patched fromEnv defaultProvider if I omit the SSO packages from the bundle. I've updated my repo with a patch for 3.502 and the new timings/bundled file sizes. I was surprised that the bundled filesizes vary so much between releases, I was expecting them to be similar in size so I might look at what changed between 3.499 and 3.502 deeper. It's still wonky that I need to mark packages as external to get the same performance, but definitely better and should greatly improve coldstart performance if someone uses the on disk version once Lambda updates their runtime to 3.502. It would still be nice if you could override the credentials provider in client config and all of the packages in the defaultProvider would treeshake out. import { fromEnv } from '@aws-sdk/credential-provider-env';
const stsClient = new STSClient({
region: process.env.AWS_REGION,
credentials: fromEnv(),
}); The way things are currently architected the defaultProvider always pulls everything in. Is there a way to specify a different runtime config? |
This shouldn't be necessary. With the introduction of async imports, bundlers should generate the unused code into separate chunks that are never loaded. If you don't mark e.g. |
I see, it's not supported at the same level as in webpack. In that case marking external for esbuild is a good way to induce the splitting. |
I tried using splitting, but it appears incompatible with the CDK esbuild wrapper which is always setting Adding:
results in:
And adding:
results in:
|
I think this can be resolved, the splitting thing is a cdk peculiarity. |
This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs and link to relevant comments in this thread. |
Checkboxes for prior research
Describe the bug
For Lambda coldstarts, it is well known creating a minified, tree-shaken bundle measurably improves performance vs. using the V3 JavaScript SDK version bundled with Lambda.
In a minified bundle, if you use any AWS client,
credential-provider-node
starts pulling inclient-sso
and other packages. These packages are unused but add > 32KB to the minified bundle. If you set thecredentials
parameter for the AWS client, it still pulls inclient-sso
and can't be tree-shaken out. Since loading credentials from environment variables is what most developers need for Lambda, there should be a way to only bundle thecredential-provider-env
credentials provider. Arguably this should be the default in the Lambda environment.SDK version number
@aws-sdk/[email protected]
Which JavaScript Runtime is this issue in?
Node.js
Details of the browser/Node.js/ReactNative version
v20.9.0
Reproduction Steps
client-sso
I've attached the metafile for the above so you can directly review it: index.meta.json
Look at it in Flamechart mode and note the inclusion of these packages:
client-sso
,token-providers
,credential-provider-sso
Screenshot of why
token-providers
is not tree-shaken:Observed Behavior
The packages
client-sso
,token-providers
andcredential-provider-sso
get bundled unnecessarily and can't be tree-shaken out.Expected Behavior
Either it uses
credential-provider-env
, or client config has some way of allowing me to omitcredential-provider-node
so the unnecessary packages can be tree-shaken out.Possible Solution
No response
Additional Information/Context
No response
The text was updated successfully, but these errors were encountered: