Waiters in modular Amazon SDK for JavaScript

TypeScript
SDK
海外精选
海外精选的内容汇集了全球优质的亚马逊云科技相关技术内容。同时,内容中提到的“AWS” 是 “Amazon Web Services” 的缩写,在此网站不作为商标展示。
0
0
{"value":"On December 15th, 2020, we announced the general availability of the AWS SDK for JavaScript, version 3 (v3). In v3, the waiters are modular and not part of the client class. In this blog post, we cover the differences between waiters in v2 and v3, and how to use them.\n\n#### **Background**\n\nWaiters make it easier to wait for a resource to transition into a desired state. This is a very common task when you’re working with services that are eventually consistent such as [Amazon DynamoDB](https://aws.amazon.com/cn/dynamodb/) or have a lead time for creating resources such as [Amazon EC2](https://aws.amazon.com/cn/ec2/). Before waiters, it was difficult to come up with the polling logic to determine whether a particular resource had transitioned into a desired state. With waiters you can more simply and easily abstract out the polling logic into a simple API call.\n\nIn v2, the waiters are bundled with the client. This increases the package size for the client. When your code does not call eventually consistent operations, you do not need waiters. In v3, the waiters are modular. You will import them only when they’re required, thus reducing your bundle size and improving performance.\n\n#### **Usage**\n\n#### **Waiters in v2**\n\nIn the example below, you create an S3 client using v2. Since the CreateBucket operation is eventually consistent, you need to call a waiter using```\\nclient.waitFor(\\"bucketExists\\")```\nbefore the operations can be performed on the bucket.\n\n```\\nJavaScript\\n```\n```\\nimport AWS from \\"aws-sdk\\";\\n\\nconst Bucket = \\"BUCKET_NAME\\";\\nconst client = new AWS.S3({ region: \\"REGION\\" });\\n\\nawait client.createBucket({ Bucket }).promise();\\nawait client.waitFor(\\"bucketExists\\", { Bucket });\\n\\n// Perform operations on Bucket, like PutObject.\\n```\n#### **Waiters in v3**\n\nIn v3, the bare-bones modular client doesn’t have waitFor operation bundled with it. You need to import the modular\n```waitUntilBucketExists```operation to check for consistency of the newly created bucket before performing operations on it.\n\n```\\nJavaScript\\n```\n```\\nimport {\\n S3Client, CreateBucketCommand, waitUntilBucketExists\\n} from \\"@aws-sdk/client-s3\\";\\n\\nconst Bucket = \\"BUCKET_NAME\\";\\nconst client = new S3Client({ region: \\"REGION\\" });\\nconst command = new CreateBucketCommand({ Bucket });\\n\\nawait client.send(command);\\nawait waitUntilBucketExists({ client, maxWaitTime: 60 }, { Bucket });\\n\\n// Perform operations on Bucket, like PutObject.\\n```\n\n\n\nIf you are looking for information on waiters in v3, you can jump to sections on [configuration options](https://aws.amazon.com/cn/blogs/developer/waiters-in-modular-aws-sdk-for-javascript/#config-minDelay-maxDelay) and [error handling](https://aws.amazon.com/cn/blogs/developer/waiters-in-modular-aws-sdk-for-javascript/#error-handling-in-v3).\n\n#### **Logging polling delays**\n\nIn the metrics shared below in this blog post, we ```\\nconsole.log```certain values in the SDK code to understand how waiters function. We also call the bucketExists waiter for a bucket which doesn’t exist in client code.\n\n#### **Log polling delay between attempts in v2**\n\nIn order to test default delay in v2, we update the code in```node_modules/aws-sdk/lib/resource_waiter.js```to console.log when```RETRY_CHECK```event listener is called.\n\n```\\nlisteners: new AWS.SequentialExecutor().addNamedListeners(function(add) {\\n add('RETRY_CHECK', 'retry', function(resp) {\\n var waiter = resp.request._waiter;\\n if (resp.error && resp.error.code === 'ResourceNotReady') {\\n resp.error.retryDelay = (waiter.config.delay || 0) * 1000;\\n }\\n+ console.log(`Delay: \${(resp.error.retryDelay/1000).toFixed(3)}s`);\\n });\\n```\nThe v2 client code which calls bucketExists waiter for bucket which doesn’t exist.\n\n```\\nJavaScript\\n```\n```\\nimport AWS from \\"aws-sdk\\";\\n\\nconst region = \\"us-west-2\\";\\nconst client = new AWS.S3({ region });\\n\\nconst Bucket = \\"test-waiters-bucket-does-not-exist\\";\\nawait client.waitFor(\\"bucketExists\\", { Bucket }).promise();\\n```\n#### **Log polling delay between attempts in v3**\nIn order to test delays in v3, we update the code in ```node_modules/@aws-sdk/util-waiter/dist/cjs/poller.js```to console.log before ```sleep```is called.\n\n```\\n+ console.log(`Delay: \${delay.toFixed(3)}s`);\\n await sleep_1.sleep(delay);\\n const { state } = await acceptorChecks(client, input);\\n```\nThe v3 client code which calls bucketExists waiter for bucket which doesn’t exist.\n\n```\\nJavaScript\\n```\n```\\nimport { S3, waitUntilBucketExists } from \\"@aws-sdk/client-s3\\";\\n\\nconst region = \\"us-west-2\\";\\nconst client = new S3({ region });\\n\\nconst Bucket = \\"test-waiters-bucket-does-not-exist\\";\\nawait waitUntilBucketExists({ client, maxWaitTime: 60 }, { Bucket });\\n```\n\n\n\n\n\n\n#### **Waiting Strategies**\n\nThe v2 follows linear backoff while waiting, while v3 follows [exponential backoff with full jitter](https://aws.amazon.com/cn/builders-library/timeouts-retries-and-backoff-with-jitter/#Jitter).\n\nThe exponential backoff with full jitter balances the cost to the caller spent waiting on a resource to stabilize, the cost of the service in responding to polling requests, and the overhead associated with potentially violating a service level agreement and getting throttled. Waiters that poll for resources that quickly stabilize will complete within the first few calls, where as waiters that could take hours to complete will send fewer requests as the number of retries increases.\n\nBy generally increasing the amount of delay between retries as the number of retry attempts increases, waiters will not overload services with unnecessary polling calls, and it protects customers from violating service level agreements that could counter-intuitively cause waiters to take longer to complete or even fail due to request throttling. By introducing randomness with jitter, waiters will retry slightly more aggressively to improve the time to completion while still maintaining the general increase in delay between retries.\n\n#### **Linear backoff in v2**\n\nOn examining the output after running client code, you will notice that a retry call is made every 5 seconds – a delay defined by S3 service for bucketExists waiter.\n\n```\\nDelay: 5.000s\\nDelay: 5.000s\\nDelay: 5.000s\\n```\n#### **Exponential backoff with full jitter in v3**\n\nOn examining the output after running client code, you will notice that the polling is done with exponential backoff starting with 5 seconds – a minDelay defined by S3 service for bucketExists waiter.\n\n```\\nDelay: 5.000s\\nDelay: 5.264s\\nDelay: 10.851s\\nDelay: 16.076s\\n```\nBecause waiters use jitter, you will get different values in your run of the example code.\n\n#### **Setting delay between request polling**\n\nBoth v2 and v3 allow you to define delay between polling requests.\n\n#### **Optional configuration delay in v2**\n\nSince v2 uses linear backoff, one value –```delay```– is used for the wait time after each poll. The waiter will use defaults provided by the service if value is not defined in waiter configuration.\n\nTo test delay value, we pass custom delay of 2 seconds in waiter configuration:\n\n```\\nJavaScript\\n```\n```\\n...\\n await client\\n .waitFor(\\"bucketExists\\", { Bucket, \$waiter: { delay: 2 } })\\n .promise();\\n...\\n```\n\n\nOn examining the output, you will notice that a retry call is made every 2 seconds:\n```\\nDelay: 2.000s\\nDelay: 2.000s\\nDelay: 2.000s\\n```\n\n#### **Optional configuration minDelay and maxDelay in v3**\n\nSince v3 uses exponential backoff with full jitter, two values – ```minDelay```and ```maxDelay``` – are used for the wait time to be computed after each poll. The waiter will use defaults provided by the service if values are not defined in the waiter configuration.\n\nAnd we pass custom minDelay and maxDelay values of 1 seconds and 10 seconds respectively in waiter configuration\n\n```\\nJavaScript\\n```\n```\\n...\\n await waitUntilBucketExists({\\n client,\\n maxWaitTime: 60,\\n minDelay: 1,\\n maxDelay: 10,\\n }, { Bucket });\\n...\\n```\nOn examining the log files, you will notice that a polling is done with a minimum delay for 1 second and maximum delay of 10 seconds as per values defined in waiter configuration.\n\n```\\nDelay: 1.000s\\nDelay: 1.257s\\nDelay: 3.202s\\nDelay: 6.744s\\nDelay: 10.000s\\n```\nIf you provide the same value for minDelay and maxDelay, then v3 will use linear backoff.\n\nIn the following code, we pass same value of 2 to minDelay as well as maxDelay:\n\n```\\nJavaScript\\n...\\n await waitUntilBucketExists({\\n client,\\n maxWaitTime: 60,\\n minDelay: 2,\\n maxDelay: 2,\\n }, { Bucket });\\n...\\n```\nOn examining the output, you will notice that a polling is done every 2 seconds:\n\n```\\nDelay: 2.000s\\nDelay: 2.000s\\nDelay: 2.000s\\n```\n\n#### **Setting maximum wait time for waiter**\n\nn v2, there is no direct way to provide maximum wait time for a waiter. You need to configure delay and maxAttempts to indirectly suggest the maximum time you want the waiter to run for. In v3, a required configuration maxWaitTime needs to be passed while calling the waiter.\n\n#### **Optional configuration maxAttempts in v2**\n\nTo test maximum wait time of 30 seconds, in v2 we configure```delay```for 5 seconds and```maxAttempts```for 6 attempts.\n```\\nJavaScript\\n```\n```\\n...\\n await client\\n .waitFor(\\"bucketExists\\", { Bucket, \$waiter: { delay: 5, maxAttempts: 6 } })\\n .promise();\\n...\\n```\n\n\nOn examining the output, you’ll see that 5 attempts are made before the waiter fails.\n\n```\\nDelay: 5.000s\\nDelay: 5.000s\\nDelay: 5.000s\\nDelay: 5.000s\\nDelay: 5.000s\\nDelay: 5.000s\\n/local/home/trivikr/workspace/test-waiters/node_modules/aws-sdk/lib/services/s3.js:698\\n resp.error = AWS.util.error(new Error(), {\\n ^\\nNotFound: Resource is not in the state bucketExists\\n```\n\n#### **Required configuration maxWaitTime in v3**\n\nTo test the maximum wait time of 30 seconds, in v3 we pass```maxWaitTime=30```in waiter configuration.\n\n```\\nJavaScript\\n```\n```\\n...\\n await waitUntilBucketExists({ client, maxWaitTime: 30 }, { Bucket });\\n...\\n```\n\nOn examining the output, you’ll see that 3 attempts are made before waiter fails because maximum wait time is reached.\n\n```\\nDelay: 5.000s\\nDelay: 8.578s\\nDelay: 7.310s\\n/local/home/trivikr/workspace/test-waiters/node_modules/@aws-sdk/util-waiter/dist/cjs/waiter.js:33\\n const timeoutError = new Error(`\${JSON.stringify({\\n ^\\nError [TimeoutError]: {\\"state\\":\\"TIMEOUT\\",\\"reason\\":\\"Waiter has timed out\\"}\\n```\n\n#### **Aborting waiter in v3 using AbortController**\n\nIn v2, there is no way to abort waiting once the waiter is called. In v3, you can pass abortSignal while calling the waiter and call abort at any point in time.\n\n#### **AbortController Interface**\n\nThe [AbortController Interface](https://dom.spec.whatwg.org/#interface-abortcontroller) provides an abort() method that toggles the state of a corresponding AbortSignal object. The API that wants to support aborting can accept an AbortSignal object, and is encouraged to respond to abort() by rejecting any unsettled promise with an```\\"AbortError\\"```.\n\n```\\nJavaScript\\n```\n```\\n// Returns a new controller whose signal is set to a newly created AbortSignal object.\\nconst controller = new AbortController();\\n\\n// Returns AbortSignal object associated with the controller.\\nconst signal = controller.signal;\\n\\n// Invoking this method will set controller’s AbortSignal's aborted flag\\n// and signal to any observers that the associated activity is to be aborted.\\ncontroller.abort();\\n```\n\n\n#### **Usage**\n\nIn v3, we added an implementation of WHATWG AbortController interface in [@aws-sdk/abort-controller](https://www.npmjs.com/package/@aws-sdk/abort-controller). To use it, you need to send AbortController.signal as abortSignal in waiter configuration when calling```.waitUntilOperationName()```operation as follows:\n\n```\\nJavaScript\\n```\n```\\nimport { AbortController } from \\"@aws-sdk/abort-controller\\";\\nimport { S3Client, waitUntilBucketExists } from \\"@aws-sdk/client-s3\\";\\n\\n...\\n\\nconst client = new S3Client(clientParams);\\nconst Bucket = \\"test-waiters-bucket-does-not-exist\\";\\n\\n// The abortController can be aborted any time.\\n// The waiter will not send any requests if abortSignal is already aborted.\\n// The existing request created by waiter will be destroyed if abortSignal\\n// is aborted before response is returned.\\nconst abortController = new AbortController();\\n\\nconst waiterPromise = waitUntilBucketExists(\\n { client, maxWaitTime: 60, abortSignal: abortController.signal },\\n { Bucket }\\n);\\n\\n// Abort after 3 seconds.\\nsetTimeout(() => {\\n abortController.abort();\\n}, 3000);\\n\\n// This will fail with \\"AbortError\\" in 3 seconds when abortSignal is aborted.\\nawait waiterPromise;\\n```\n\n\nAlternatively, you can substitute AbortController in```@aws-sdk/abort-controller```with any other WHATWG AbortController interface, like [AbortController Web API](https://developer.mozilla.org/en-US/docs/Web/API/AbortController) or [abort-controller](abort-controller) npm package or [Node.js AbortController implementation](https://nodejs.org/api/globals.html#globals_class_abortcontroller).\n\n#### **Error Handling**\n\nThe errors thrown by waiters can be handled using [try…catch](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch) statements. Since the waiter returns a promise, you can also use [Promise.prototype.catch()](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch). In v2, the waiters also support callbacks which are not supported in v3. The section below will show examples with try..catch statements.\n\n#### **Error Handling in v2**\n\nIn v2, the waiter re-throws the error returned by the last operation which was attempted. For example, the following code shows Timeout Error:\n\n```\\nJavaScript\\n```\n```\\n// ...\\nconst Bucket = \\"test-waiters-bucket-does-not-exist\\";\\ntry {\\n await client\\n .waitFor(\\"bucketExists\\", { Bucket, \$waiter: { delay: 2, maxAttempts: 3 } })\\n .promise();\\n} catch (error) {\\n // error.name is \\"NotFound\\" and error.code is \\"ResourceNotReady\\" from the\\n // pooling operation headBucket used for waiting\\n}\\n```\n\n\n\n#### **Error Handling in v3**\n\nn v3, the waiter throws a specific error with information about the state of the waiter when the error was thrown. For example, the following code shows Timeout Error:\n\n```\\nJavaScript\\n```\n```\\n// ...\\nconst Bucket = \\"test-waiters-bucket-does-not-exist\\";\\ntry {\\n await waitUntilBucketExists({ client, maxWaitTime: 10 }, { Bucket });\\n} catch (error) {\\n // error.name is \\"TimeoutError\\" and error.state is \\"TIMEOUT\\"\\n}\\n```\n\n\n#### **Feedback**\n\nWe value your feedback, so please tell us what you like and don’t like by opening [an issue on GitHub](https://github.com/aws/aws-sdk-js-v3/issues/new/choose).\n\n![image.png](https://dev-media.amazoncloud.cn/177427e8624a4e34bd6907b0980bcc1e_image.png)[**Trivikram Kamat**](https://twitter.com/trivikram)\n\nTrivikram is maintainer of AWS SDK for JavaScript in Node.js and browser. Trivikram is also a Node.js Core collaborator and have contributed to HTTP, HTTP/2 and HTTP/3 over QUIC implementations in the past. He has been writing JavaScript for over a decade. You can find him on Twitter [@trivikram](https://twitter.com/trivikram) and GitHub [@trivikr](https://twitter.com/trivikram).\n\nTAGS: [aws-sdk](https://aws.amazon.com/cn/blogs/developer/tag/aws-sdk/), [aws-sdk-js](https://aws.amazon.com/cn/blogs/developer/tag/aws-sdk-js/), [aws-sdk-js-v3](https://aws.amazon.com/cn/blogs/developer/tag/aws-sdk-js-v3/), [browser](https://aws.amazon.com/cn/blogs/developer/tag/browser/), [JavaScript](https://aws.amazon.com/cn/blogs/developer/tag/javascript/), [Node.js](https://aws.amazon.com/cn/blogs/developer/tag/node-js/), [react-native](https://aws.amazon.com/cn/blogs/developer/tag/react-native/), [SDK](https://aws.amazon.com/cn/blogs/developer/tag/sdk/), [typescript](https://aws.amazon.com/cn/blogs/developer/tag/typescript/)\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n\n \n\n\n\n\n\n\n\n\n\n\n\n\n\n\n","render":"<p>On December 15th, 2020, we announced the general availability of the AWS SDK for JavaScript, version 3 (v3). In v3, the waiters are modular and not part of the client class. In this blog post, we cover the differences between waiters in v2 and v3, and how to use them.</p>\n<h4><a id=\\"Background_2\\"></a><strong>Background</strong></h4>\\n<p>Waiters make it easier to wait for a resource to transition into a desired state. This is a very common task when you’re working with services that are eventually consistent such as <a href=\\"https://aws.amazon.com/cn/dynamodb/\\" target=\\"_blank\\">Amazon DynamoDB</a> or have a lead time for creating resources such as <a href=\\"https://aws.amazon.com/cn/ec2/\\" target=\\"_blank\\">Amazon EC2</a>. Before waiters, it was difficult to come up with the polling logic to determine whether a particular resource had transitioned into a desired state. With waiters you can more simply and easily abstract out the polling logic into a simple API call.</p>\\n<p>In v2, the waiters are bundled with the client. This increases the package size for the client. When your code does not call eventually consistent operations, you do not need waiters. In v3, the waiters are modular. You will import them only when they’re required, thus reducing your bundle size and improving performance.</p>\n<h4><a id=\\"Usage_8\\"></a><strong>Usage</strong></h4>\\n<h4><a id=\\"Waiters_in_v2_10\\"></a><strong>Waiters in v2</strong></h4>\\n<p>In the example below, you create an S3 client using v2. Since the CreateBucket operation is eventually consistent, you need to call a waiter using<code> client.waitFor(&quot;bucketExists&quot;)</code><br />\\nbefore the operations can be performed on the bucket.</p>\n<pre><code class=\\"lang-\\">JavaScript\\n</code></pre>\\n<pre><code class=\\"lang-\\">import AWS from &quot;aws-sdk&quot;;\\n\\nconst Bucket = &quot;BUCKET_NAME&quot;;\\nconst client = new AWS.S3({ region: &quot;REGION&quot; });\\n\\nawait client.createBucket({ Bucket }).promise();\\nawait client.waitFor(&quot;bucketExists&quot;, { Bucket });\\n\\n// Perform operations on Bucket, like PutObject.\\n</code></pre>\\n<h4><a id=\\"Waiters_in_v3_30\\"></a><strong>Waiters in v3</strong></h4>\\n<p>In v3, the bare-bones modular client doesn’t have waitFor operation bundled with it. You need to import the modular<br />\\n<code>waitUntilBucketExists</code>operation to check for consistency of the newly created bucket before performing operations on it.</p>\\n<pre><code class=\\"lang-\\">JavaScript\\n</code></pre>\\n<pre><code class=\\"lang-\\">import {\\n S3Client, CreateBucketCommand, waitUntilBucketExists\\n} from &quot;@aws-sdk/client-s3&quot;;\\n\\nconst Bucket = &quot;BUCKET_NAME&quot;;\\nconst client = new S3Client({ region: &quot;REGION&quot; });\\nconst command = new CreateBucketCommand({ Bucket });\\n\\nawait client.send(command);\\nawait waitUntilBucketExists({ client, maxWaitTime: 60 }, { Bucket });\\n\\n// Perform operations on Bucket, like PutObject.\\n</code></pre>\\n<p>If you are looking for information on waiters in v3, you can jump to sections on <a href=\\"https://aws.amazon.com/cn/blogs/developer/waiters-in-modular-aws-sdk-for-javascript/#config-minDelay-maxDelay\\" target=\\"_blank\\">configuration options</a> and <a href=\\"https://aws.amazon.com/cn/blogs/developer/waiters-in-modular-aws-sdk-for-javascript/#error-handling-in-v3\\" target=\\"_blank\\">error handling</a>.</p>\\n<h4><a id=\\"Logging_polling_delays_57\\"></a><strong>Logging polling delays</strong></h4>\\n<p>In the metrics shared below in this blog post, we <code> console.log</code>certain values in the SDK code to understand how waiters function. We also call the bucketExists waiter for a bucket which doesn’t exist in client code.</p>\\n<h4><a id=\\"Log_polling_delay_between_attempts_in_v2_62\\"></a><strong>Log polling delay between attempts in v2</strong></h4>\\n<p>In order to test default delay in v2, we update the code in<code>node_modules/aws-sdk/lib/resource_waiter.js</code>to console.log when<code>RETRY_CHECK</code>event listener is called.</p>\\n<pre><code class=\\"lang-\\">listeners: new AWS.SequentialExecutor().addNamedListeners(function(add) {\\n add('RETRY_CHECK', 'retry', function(resp) {\\n var waiter = resp.request._waiter;\\n if (resp.error &amp;&amp; resp.error.code === 'ResourceNotReady') {\\n resp.error.retryDelay = (waiter.config.delay || 0) * 1000;\\n }\\n+ console.log(`Delay: \${(resp.error.retryDelay/1000).toFixed(3)}s`);\\n });\\n</code></pre>\\n<p>The v2 client code which calls bucketExists waiter for bucket which doesn’t exist.</p>\n<pre><code class=\\"lang-\\">JavaScript\\n</code></pre>\\n<pre><code class=\\"lang-\\">import AWS from &quot;aws-sdk&quot;;\\n\\nconst region = &quot;us-west-2&quot;;\\nconst client = new AWS.S3({ region });\\n\\nconst Bucket = &quot;test-waiters-bucket-does-not-exist&quot;;\\nawait client.waitFor(&quot;bucketExists&quot;, { Bucket }).promise();\\n</code></pre>\\n<h4><a id=\\"Log_polling_delay_between_attempts_in_v3_90\\"></a><strong>Log polling delay between attempts in v3</strong></h4>\\n<p>In order to test delays in v3, we update the code in <code>node_modules/@aws-sdk/util-waiter/dist/cjs/poller.js</code>to console.log before <code>sleep</code>is called.</p>\\n<pre><code class=\\"lang-\\">+ console.log(`Delay: \${delay.toFixed(3)}s`);\\n await sleep_1.sleep(delay);\\n const { state } = await acceptorChecks(client, input);\\n</code></pre>\\n<p>The v3 client code which calls bucketExists waiter for bucket which doesn’t exist.</p>\n<pre><code class=\\"lang-\\">JavaScript\\n</code></pre>\\n<pre><code class=\\"lang-\\">import { S3, waitUntilBucketExists } from &quot;@aws-sdk/client-s3&quot;;\\n\\nconst region = &quot;us-west-2&quot;;\\nconst client = new S3({ region });\\n\\nconst Bucket = &quot;test-waiters-bucket-does-not-exist&quot;;\\nawait waitUntilBucketExists({ client, maxWaitTime: 60 }, { Bucket });\\n</code></pre>\\n<h4><a id=\\"Waiting_Strategies_118\\"></a><strong>Waiting Strategies</strong></h4>\\n<p>The v2 follows linear backoff while waiting, while v3 follows <a href=\\"https://aws.amazon.com/cn/builders-library/timeouts-retries-and-backoff-with-jitter/#Jitter\\" target=\\"_blank\\">exponential backoff with full jitter</a>.</p>\\n<p>The exponential backoff with full jitter balances the cost to the caller spent waiting on a resource to stabilize, the cost of the service in responding to polling requests, and the overhead associated with potentially violating a service level agreement and getting throttled. Waiters that poll for resources that quickly stabilize will complete within the first few calls, where as waiters that could take hours to complete will send fewer requests as the number of retries increases.</p>\n<p>By generally increasing the amount of delay between retries as the number of retry attempts increases, waiters will not overload services with unnecessary polling calls, and it protects customers from violating service level agreements that could counter-intuitively cause waiters to take longer to complete or even fail due to request throttling. By introducing randomness with jitter, waiters will retry slightly more aggressively to improve the time to completion while still maintaining the general increase in delay between retries.</p>\n<h4><a id=\\"Linear_backoff_in_v2_126\\"></a><strong>Linear backoff in v2</strong></h4>\\n<p>On examining the output after running client code, you will notice that a retry call is made every 5 seconds – a delay defined by S3 service for bucketExists waiter.</p>\n<pre><code class=\\"lang-\\">Delay: 5.000s\\nDelay: 5.000s\\nDelay: 5.000s\\n</code></pre>\\n<h4><a id=\\"Exponential_backoff_with_full_jitter_in_v3_135\\"></a><strong>Exponential backoff with full jitter in v3</strong></h4>\\n<p>On examining the output after running client code, you will notice that the polling is done with exponential backoff starting with 5 seconds – a minDelay defined by S3 service for bucketExists waiter.</p>\n<pre><code class=\\"lang-\\">Delay: 5.000s\\nDelay: 5.264s\\nDelay: 10.851s\\nDelay: 16.076s\\n</code></pre>\\n<p>Because waiters use jitter, you will get different values in your run of the example code.</p>\n<h4><a id=\\"Setting_delay_between_request_polling_147\\"></a><strong>Setting delay between request polling</strong></h4>\\n<p>Both v2 and v3 allow you to define delay between polling requests.</p>\n<h4><a id=\\"Optional_configuration_delay_in_v2_151\\"></a><strong>Optional configuration delay in v2</strong></h4>\\n<p>Since v2 uses linear backoff, one value –<code>delay</code>– is used for the wait time after each poll. The waiter will use defaults provided by the service if value is not defined in waiter configuration.</p>\\n<p>To test delay value, we pass custom delay of 2 seconds in waiter configuration:</p>\n<pre><code class=\\"lang-\\">JavaScript\\n</code></pre>\\n<pre><code class=\\"lang-\\">...\\n await client\\n .waitFor(&quot;bucketExists&quot;, { Bucket, \$waiter: { delay: 2 } })\\n .promise();\\n...\\n</code></pre>\\n<p>On examining the output, you will notice that a retry call is made every 2 seconds:</p>\n<pre><code class=\\"lang-\\">Delay: 2.000s\\nDelay: 2.000s\\nDelay: 2.000s\\n</code></pre>\\n<h4><a id=\\"Optional_configuration_minDelay_and_maxDelay_in_v3_176\\"></a><strong>Optional configuration minDelay and maxDelay in v3</strong></h4>\\n<p>Since v3 uses exponential backoff with full jitter, two values – <code>minDelay</code>and <code>maxDelay</code> – are used for the wait time to be computed after each poll. The waiter will use defaults provided by the service if values are not defined in the waiter configuration.</p>\\n<p>And we pass custom minDelay and maxDelay values of 1 seconds and 10 seconds respectively in waiter configuration</p>\n<pre><code class=\\"lang-\\">JavaScript\\n</code></pre>\\n<pre><code class=\\"lang-\\">...\\n await waitUntilBucketExists({\\n client,\\n maxWaitTime: 60,\\n minDelay: 1,\\n maxDelay: 10,\\n }, { Bucket });\\n...\\n</code></pre>\\n<p>On examining the log files, you will notice that a polling is done with a minimum delay for 1 second and maximum delay of 10 seconds as per values defined in waiter configuration.</p>\n<pre><code class=\\"lang-\\">Delay: 1.000s\\nDelay: 1.257s\\nDelay: 3.202s\\nDelay: 6.744s\\nDelay: 10.000s\\n</code></pre>\\n<p>If you provide the same value for minDelay and maxDelay, then v3 will use linear backoff.</p>\n<p>In the following code, we pass same value of 2 to minDelay as well as maxDelay:</p>\n<pre><code class=\\"lang-\\">JavaScript\\n...\\n await waitUntilBucketExists({\\n client,\\n maxWaitTime: 60,\\n minDelay: 2,\\n maxDelay: 2,\\n }, { Bucket });\\n...\\n</code></pre>\\n<p>On examining the output, you will notice that a polling is done every 2 seconds:</p>\n<pre><code class=\\"lang-\\">Delay: 2.000s\\nDelay: 2.000s\\nDelay: 2.000s\\n</code></pre>\\n<h4><a id=\\"Setting_maximum_wait_time_for_waiter_227\\"></a><strong>Setting maximum wait time for waiter</strong></h4>\\n<p>n v2, there is no direct way to provide maximum wait time for a waiter. You need to configure delay and maxAttempts to indirectly suggest the maximum time you want the waiter to run for. In v3, a required configuration maxWaitTime needs to be passed while calling the waiter.</p>\n<h4><a id=\\"Optional_configuration_maxAttempts_in_v2_231\\"></a><strong>Optional configuration maxAttempts in v2</strong></h4>\\n<p>To test maximum wait time of 30 seconds, in v2 we configure<code>delay</code>for 5 seconds and<code>maxAttempts</code>for 6 attempts.</p>\\n<pre><code class=\\"lang-\\">JavaScript\\n</code></pre>\\n<pre><code class=\\"lang-\\">...\\n await client\\n .waitFor(&quot;bucketExists&quot;, { Bucket, \$waiter: { delay: 5, maxAttempts: 6 } })\\n .promise();\\n...\\n</code></pre>\\n<p>On examining the output, you’ll see that 5 attempts are made before the waiter fails.</p>\n<pre><code class=\\"lang-\\">Delay: 5.000s\\nDelay: 5.000s\\nDelay: 5.000s\\nDelay: 5.000s\\nDelay: 5.000s\\nDelay: 5.000s\\n/local/home/trivikr/workspace/test-waiters/node_modules/aws-sdk/lib/services/s3.js:698\\n resp.error = AWS.util.error(new Error(), {\\n ^\\nNotFound: Resource is not in the state bucketExists\\n</code></pre>\\n<h4><a id=\\"Required_configuration_maxWaitTime_in_v3_261\\"></a><strong>Required configuration maxWaitTime in v3</strong></h4>\\n<p>To test the maximum wait time of 30 seconds, in v3 we pass<code>maxWaitTime=30</code>in waiter configuration.</p>\\n<pre><code class=\\"lang-\\">JavaScript\\n</code></pre>\\n<pre><code class=\\"lang-\\">...\\n await waitUntilBucketExists({ client, maxWaitTime: 30 }, { Bucket });\\n...\\n</code></pre>\\n<p>On examining the output, you’ll see that 3 attempts are made before waiter fails because maximum wait time is reached.</p>\n<pre><code class=\\"lang-\\">Delay: 5.000s\\nDelay: 8.578s\\nDelay: 7.310s\\n/local/home/trivikr/workspace/test-waiters/node_modules/@aws-sdk/util-waiter/dist/cjs/waiter.js:33\\n const timeoutError = new Error(`\${JSON.stringify({\\n ^\\nError [TimeoutError]: {&quot;state&quot;:&quot;TIMEOUT&quot;,&quot;reason&quot;:&quot;Waiter has timed out&quot;}\\n</code></pre>\\n<h4><a id=\\"Aborting_waiter_in_v3_using_AbortController_286\\"></a><strong>Aborting waiter in v3 using AbortController</strong></h4>\\n<p>In v2, there is no way to abort waiting once the waiter is called. In v3, you can pass abortSignal while calling the waiter and call abort at any point in time.</p>\n<h4><a id=\\"AbortController_Interface_290\\"></a><strong>AbortController Interface</strong></h4>\\n<p>The <a href=\\"https://dom.spec.whatwg.org/#interface-abortcontroller\\" target=\\"_blank\\">AbortController Interface</a> provides an abort() method that toggles the state of a corresponding AbortSignal object. The API that wants to support aborting can accept an AbortSignal object, and is encouraged to respond to abort() by rejecting any unsettled promise with an<code>&quot;AbortError&quot;</code>.</p>\\n<pre><code class=\\"lang-\\">JavaScript\\n</code></pre>\\n<pre><code class=\\"lang-\\">// Returns a new controller whose signal is set to a newly created AbortSignal object.\\nconst controller = new AbortController();\\n\\n// Returns AbortSignal object associated with the controller.\\nconst signal = controller.signal;\\n\\n// Invoking this method will set controller’s AbortSignal's aborted flag\\n// and signal to any observers that the associated activity is to be aborted.\\ncontroller.abort();\\n</code></pre>\\n<h4><a id=\\"Usage_310\\"></a><strong>Usage</strong></h4>\\n<p>In v3, we added an implementation of WHATWG AbortController interface in <a href=\\"https://www.npmjs.com/package/@aws-sdk/abort-controller\\" target=\\"_blank\\">@aws-sdk/abort-controller</a>. To use it, you need to send AbortController.signal as abortSignal in waiter configuration when calling<code>.waitUntilOperationName()</code>operation as follows:</p>\\n<pre><code class=\\"lang-\\">JavaScript\\n</code></pre>\\n<pre><code class=\\"lang-\\">import { AbortController } from &quot;@aws-sdk/abort-controller&quot;;\\nimport { S3Client, waitUntilBucketExists } from &quot;@aws-sdk/client-s3&quot;;\\n\\n...\\n\\nconst client = new S3Client(clientParams);\\nconst Bucket = &quot;test-waiters-bucket-does-not-exist&quot;;\\n\\n// The abortController can be aborted any time.\\n// The waiter will not send any requests if abortSignal is already aborted.\\n// The existing request created by waiter will be destroyed if abortSignal\\n// is aborted before response is returned.\\nconst abortController = new AbortController();\\n\\nconst waiterPromise = waitUntilBucketExists(\\n { client, maxWaitTime: 60, abortSignal: abortController.signal },\\n { Bucket }\\n);\\n\\n// Abort after 3 seconds.\\nsetTimeout(() =&gt; {\\n abortController.abort();\\n}, 3000);\\n\\n// This will fail with &quot;AbortError&quot; in 3 seconds when abortSignal is aborted.\\nawait waiterPromise;\\n</code></pre>\\n<p>Alternatively, you can substitute AbortController in<code>@aws-sdk/abort-controller</code>with any other WHATWG AbortController interface, like <a href=\\"https://developer.mozilla.org/en-US/docs/Web/API/AbortController\\" target=\\"_blank\\">AbortController Web API</a> or <a href=\\"abort-controller\\" target=\\"_blank\\">abort-controller</a> npm package or <a href=\\"https://nodejs.org/api/globals.html#globals_class_abortcontroller\\" target=\\"_blank\\">Node.js AbortController implementation</a>.</p>\\n<h4><a id=\\"Error_Handling_349\\"></a><strong>Error Handling</strong></h4>\\n<p>The errors thrown by waiters can be handled using <a href=\\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/try...catch\\" target=\\"_blank\\">try…catch</a> statements. Since the waiter returns a promise, you can also use <a href=\\"https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/catch\\" target=\\"_blank\\">Promise.prototype.catch()</a>. In v2, the waiters also support callbacks which are not supported in v3. The section below will show examples with try…catch statements.</p>\\n<h4><a id=\\"Error_Handling_in_v2_353\\"></a><strong>Error Handling in v2</strong></h4>\\n<p>In v2, the waiter re-throws the error returned by the last operation which was attempted. For example, the following code shows Timeout Error:</p>\n<pre><code class=\\"lang-\\">JavaScript\\n</code></pre>\\n<pre><code class=\\"lang-\\">// ...\\nconst Bucket = &quot;test-waiters-bucket-does-not-exist&quot;;\\ntry {\\n await client\\n .waitFor(&quot;bucketExists&quot;, { Bucket, \$waiter: { delay: 2, maxAttempts: 3 } })\\n .promise();\\n} catch (error) {\\n // error.name is &quot;NotFound&quot; and error.code is &quot;ResourceNotReady&quot; from the\\n // pooling operation headBucket used for waiting\\n}\\n</code></pre>\\n<h4><a id=\\"Error_Handling_in_v3_375\\"></a><strong>Error Handling in v3</strong></h4>\\n<p>n v3, the waiter throws a specific error with information about the state of the waiter when the error was thrown. For example, the following code shows Timeout Error:</p>\n<pre><code class=\\"lang-\\">JavaScript\\n</code></pre>\\n<pre><code class=\\"lang-\\">// ...\\nconst Bucket = &quot;test-waiters-bucket-does-not-exist&quot;;\\ntry {\\n await waitUntilBucketExists({ client, maxWaitTime: 10 }, { Bucket });\\n} catch (error) {\\n // error.name is &quot;TimeoutError&quot; and error.state is &quot;TIMEOUT&quot;\\n}\\n</code></pre>\\n<h4><a id=\\"Feedback_393\\"></a><strong>Feedback</strong></h4>\\n<p>We value your feedback, so please tell us what you like and don’t like by opening <a href=\\"https://github.com/aws/aws-sdk-js-v3/issues/new/choose\\" target=\\"_blank\\">an issue on GitHub</a>.</p>\\n<p><img src=\\"https://dev-media.amazoncloud.cn/177427e8624a4e34bd6907b0980bcc1e_image.png\\" alt=\\"image.png\\" /><a href=\\"https://twitter.com/trivikram\\" target=\\"_blank\\"><strong>Trivikram Kamat</strong></a></p>\n<p>Trivikram is maintainer of AWS SDK for JavaScript in Node.js and browser. Trivikram is also a Node.js Core collaborator and have contributed to HTTP, HTTP/2 and HTTP/3 over QUIC implementations in the past. He has been writing JavaScript for over a decade. You can find him on Twitter <a href=\\"https://twitter.com/trivikram\\" target=\\"_blank\\">@trivikram</a> and GitHub <a href=\\"https://twitter.com/trivikram\\" target=\\"_blank\\">@trivikr</a>.</p>\\n<p>TAGS: <a href=\\"https://aws.amazon.com/cn/blogs/developer/tag/aws-sdk/\\" target=\\"_blank\\">aws-sdk</a>, <a href=\\"https://aws.amazon.com/cn/blogs/developer/tag/aws-sdk-js/\\" target=\\"_blank\\">aws-sdk-js</a>, <a href=\\"https://aws.amazon.com/cn/blogs/developer/tag/aws-sdk-js-v3/\\" target=\\"_blank\\">aws-sdk-js-v3</a>, <a href=\\"https://aws.amazon.com/cn/blogs/developer/tag/browser/\\" target=\\"_blank\\">browser</a>, <a href=\\"https://aws.amazon.com/cn/blogs/developer/tag/javascript/\\" target=\\"_blank\\">JavaScript</a>, <a href=\\"https://aws.amazon.com/cn/blogs/developer/tag/node-js/\\" target=\\"_blank\\">Node.js</a>, <a href=\\"https://aws.amazon.com/cn/blogs/developer/tag/react-native/\\" target=\\"_blank\\">react-native</a>, <a href=\\"https://aws.amazon.com/cn/blogs/developer/tag/sdk/\\" target=\\"_blank\\">SDK</a>, <a href=\\"https://aws.amazon.com/cn/blogs/developer/tag/typescript/\\" target=\\"_blank\\">typescript</a></p>\n"}
目录
亚马逊云科技解决方案 基于行业客户应用场景及技术领域的解决方案
联系亚马逊云科技专家
亚马逊云科技解决方案
基于行业客户应用场景及技术领域的解决方案
联系专家
0
目录
关闭