Open GovernmentHack opened 1 year ago
Hi @GovernmentHack ,
The client will only attempt a retry if the error that is being thrown is a Retryable Error. Client errors are not retryable, so it doesn't matter which number of retries you have there.
In your first workaround, you are effectively forcing the retryer to treat CREDENTIALS_PROVIDER_ERROR
as a retryable error.
Is there a specific reason of why you are setting your credential provider this way? Why not just configure your ~/.aws/credentials
file and let the SDK credential chain resolve those automatically?
Thanks, Ran~
Why not just configure your ~/.aws/credentials file and let the SDK credential chain resolve those automatically?
Our production environment provides the credentials from an IAM policy, and by using the fromNodeProviderChain
we're still essentially using the provider chain, while "injecting" the missing parameter which typescript otherwise blocks us from setting.
The client will only attempt a retry if the error that is being thrown is a Retryable Error
I've seen that logic with the retry middleware, but it seems the credentials provider doesn't use that. I believe ultimately the remoteProvider()
is called from the provider chain based on our usage of IAM policies, which will call the fromInstanceMetadata() provider, right? That provider doesn't seem to use the same retryable logic used by the "@aws-sdk/service-error-classification"
package, which is what the middleware-retry package seems to use. It instead uses this retry function
code snippet from the getInstanceImdsProvider()
used by fromInstanceMetadata()
code:
import { retry } from "./remoteProvider/retry";
// ...
const getCredentials = async (maxRetries: number, options: RequestOptions) => {
const profile = (
await retry<string>(async () => {
let profile: string;
try {
profile = await getProfile(options);
} catch (err) {
if (err.statusCode === 401) {
disableFetchToken = false;
}
throw err;
}
return profile;
}, maxRetries)
).trim();
return retry(async () => {
let creds: AwsCredentialIdentity;
try {
creds = await getCredentialsFromProfile(profile, options);
} catch (err) {
if (err.statusCode === 401) {
disableFetchToken = false;
}
throw err;
}
return creds;
}, maxRetries);
};
Just had the same issue with "@aws-sdk/client-sqs": "^3.245.0"
(thanks to @RanVaknin for the code to manually setup the node provider - worked a treat!).
For more context: we are using ECS, and i assume the credentials provider chain needs to be able to retry because the container can't initially access the aws endpoint it needs to get it's auth tokens. Could be considered a bug in ECS for that reason, but this is working for us in other v3 SDKs (and v2 in general).
Same issue with
"@aws-sdk/client-secrets-manager": "^3.496.0"
Checkboxes for prior research
Describe the bug
The AWS SQS Client does not retry to get credentials when
maxAttempts
is set in the initial client configuration.I believe the
DefaultProvider
credentials provider from the credential-provider-node which is used in the SQS Client does not use themaxAttempts
configuration parameter, and therefore defaults to 0 retries always.From digging through the source code, I believe that when the defaultCredentialsProvider (initially set here) is accessed (used here), and given the initial configuration (see the
init
value passed through the chain), the configuredmaxAttempts
as a parameter for how many times to retry (defined as a type here) is not used.Instead, the parameter
maxRetries
from theproviderConfigFromInit()
function (here) is used for retries in the credentials provider. Since this parameter is not set, nor part of the type definition, it is then defaulted to the default value of 0 (default and fallback logic here), therefore the credentials provider is never retried.SDK version number
@aws-sdk/client-sqs@3.231.0
Which JavaScript Runtime is this issue in?
Node.js
Details of the browser/Node.js/ReactNative version
v18.12.1
Reproduction Steps
* Reproduction is tricky, as it requires a cloud environment (node server hosted on ECS, with credentials provided by IAM), and the credentials provider to be "flakey", (e.g. it fails a request for credentials once every so often)
Simply make an SQS client request like such:
Observed Behavior
When we get the transient errors, they are as follows:
Expected Behavior
We expect more than 1 attempt to be made in trying to get credentials.
Ideally an attempt would be successful. But if none were, we'd still see the
error.$metadata.attempts
value to be5
given ourmaxAttempts
configuration.Possible Solution
We have been able to overcome this issue via 2 work-arounds:
const sqsClient = new SQSClient({ endpoint: MY_ENDPOINT, region: MY_REGION, maxAttempts: 5, credentialDefaultProvider: (input: any) => fromNodeProviderChain({ ...input, maxRetries: 3 }), });