AWS SDK for PHP版本 3 中的承諾 - AWS SDK for PHP

本文為英文版的機器翻譯版本,如內容有任何歧義或不一致之處,概以英文版為準。

AWS SDK for PHP版本 3 中的承諾

AWS SDK for PHP使用 promise 達成非同步工作流程,而這種非同步性讓您能夠並行傳送 HTTP 請求。由開發套件使用的 promise 規格是 Promises/A+

什麼是承諾?

Promise 代表非同步操作的最終結果。與 promise 主要互動的方式,是透過其 then 方法。此方法註冊回呼以接收 promise 的最終值或 promise 無法履行的理由。

AWS SDK for PHP倚賴 guzzlehttp/promises Composer 套件進行 promise 實作。Guzzle promises 支援封鎖和非封鎖的工作流程,並可與任何非封鎖事件迴圈一起使用。

注意

HTTP 請求在AWS SDK for PHP中使用單一執行緒同時發送,其中非封鎖呼叫用於傳輸一個以上的 HTTP 請求,同時回應狀態更改 (例如,履行或拒絕 promise)。

開發套件中的 Promise

Promise 用於整個軟體開發套件。例如,promise 用於由開發套件所提供的大多數高階抽象概念:分頁程式等待程式命令集區分段上傳S3 目錄/儲存貯體傳輸等。

當您呼叫用任何 Async 非同步尾碼方法時,開發套件提供的所有用戶端都會傳回 promise。例如,下列程式碼示範如何建立承諾以取得 Amazon DynamoDB DescribeTable 作業的結果。

$client = new Aws\DynamoDb\DynamoDbClient([ 'region' => 'us-west-2', 'version' => 'latest', ]); // This will create a promise that will eventually contain a result $promise = $client->describeTableAsync(['TableName' => 'mytable']);

請注意,您可以呼叫 describeTabledescribeTableAsync。這些方法是由 API 模型和與用戶端關聯的 __call 編號支援的用戶端神奇 version 方法。透過呼叫不帶 describeTable 尾碼的 Async 方法,用戶端將在傳送 HTTP 請求時封鎖,並返回 Aws\ResultInterface 物件或擲出 Aws\Exception\AwsException。透過用 Async (即 describeTableAsync) 添加操作名稱尾碼,用戶端將建立一個最終由 Aws\ResultInterface 物件履行或被 Aws\Exception\AwsException 拒絕的 promise。

重要

當 promise 傳回時,結果可能已經到達 (例如,當使用模擬處理常式時),或者 HTTP 請求可能沒有啟動。

您可以使用 then 方法以 promise 註冊回呼。該方法接受兩個回呼,$onFulfilled$onRejected,兩者都是非必要的。如果 promise 已履行,則會呼叫 $onFulfilled 回呼,如果 promise 被拒絕 (代表失敗),則會呼叫 $onRejected 回呼。

$promise->then( function ($value) { echo "The promise was fulfilled with {$value}"; }, function ($reason) { echo "The promise was rejected with {$reason}"; } );

同時執行命令

多個 promise 可以組合在一起,以便同時執行。這可以透過將軟體開發套件與非封鎖事件迴路整合,或透過建立多個 promise 並等待它們同時完成來實現。

use GuzzleHttp\Promise\Utils; $sdk = new Aws\Sdk([ 'version' => 'latest', 'region' => 'us-east-1' ]); $s3 = $sdk->createS3(); $ddb = $sdk->createDynamoDb(); $promises = [ 'buckets' => $s3->listBucketsAsync(), 'tables' => $ddb->listTablesAsync(), ]; // Wait for both promises to complete. $results = Utils::unwrap($promises); // Notice that this method will maintain the input array keys. var_dump($results['buckets']->toArray()); var_dump($results['tables']->toArray());
注意

CommandPool供更強大的機制,可同時執行多個 API 作業。

鏈接承諾

Promise 的好處之一是它們可以組合,可讓您建立轉換管道。Promise 是由鏈結 then 回呼與後續 then 回呼構成。then 方法傳回的值是根據提供的回呼結果履行或拒絕的 promise。

$promise = $client->describeTableAsync(['TableName' => 'mytable']); $promise ->then( function ($value) { $value['AddedAttribute'] = 'foo'; return $value; }, function ($reason) use ($client) { // The call failed. You can recover from the error here and // return a value that will be provided to the next successful // then() callback. Let's retry the call. return $client->describeTableAsync(['TableName' => 'mytable']); } )->then( function ($value) { // This is only invoked when the previous then callback is // fulfilled. If the previous callback returned a promise, then // this callback is invoked only after that promise is // fulfilled. echo $value['AddedAttribute']; // outputs "foo" }, function ($reason) { // The previous callback was rejected (failed). } );
注意

Promise 回呼的傳回值是提供給下游 promise 的 $value 引數。如果您要為下游 provide 鏈提供值,則必須在回呼函數中傳回一個值。

拒絕轉發

promise 被拒絕時,您可以註冊一個回呼以呼叫。如果在任何回呼中擲出例外,promise 將被例外拒絕,且鏈中的下一個 promise 將被拒絕並產生例外。如果您從 $onRejected 回呼成功傳回一個值,則 promise 鏈中的下一個 promise 將使用來自 $onRejected 回呼傳回的值以履行。

等待承諾

您可以透過使用 promise 的 wait 方法同步強制 promise 完成。

$promise = $client->listTablesAsync(); $result = $promise->wait();

如果在呼叫 promise 的 wait 函數時遇到例外,那麼 promise 會被例外拒絕,且會擲出該例外。

use Aws\Exception\AwsException; $promise = $client->listTablesAsync(); try { $result = $promise->wait(); } catch (AwsException $e) { // Handle the error }

在已履行的 promise 上呼叫 wait 不會觸發等待函數。它只會傳回之前傳送的值。

$promise = $client->listTablesAsync(); $result = $promise->wait(); assert($result ### $promise->wait());

在已拒絕的 promise 上呼叫 wait 會擲出例外。如果拒絕原因是 \Exception 的一個執行個體,則擲出原因。否則,會擲出 GuzzleHttp\Promise\RejectionException,並且可以透過呼叫例外的 getReason 方法來獲取原因。

注意

AWS SDK for PHP的 API 操作呼叫遭到 Aws\Exception\AwsException 類別的子類別拒絕。但是,交付給 then 方法的原因可能不同,因為增加了變更拒絕原因的自訂中介軟體。

取消承諾

可以使用 promise 的 cancel() 方法取消 promise。如果 promise 已經解決,呼叫 cancel() 將不會生效。取消一個 promise 會取消該 promise,和任何等待該 promise 交付的 promise。一個遭到取消的 promise 會被 GuzzleHttp\Promise\RejectionException 拒絕。

結合承諾

您可以將 promise 結合到彙整 promise 中以建構更複雜的工作流程。guzzlehttp/promise 套件包含各種可用於結合 promise 的函數。

您可以在命名空間-.Promise 中找到所有承諾集合函數的 API 文檔GuzzleHttp。

each 和 each_limit

CommandPool當你有一個Aws\CommandInterface命令的任務隊列時,使用固定池大小同時執行(這些命令可以在內存中或由延遲迭代器產生)。CommandPool 確保同時傳送固定數量的命令,直到提供的反覆運算器耗盡為止。

CommandPool 僅適用於由同一用戶端執行的命令。您可以使用 GuzzleHttp\Promise\each_limit 函數,使用固定的集區大小同時執行不同用戶端的傳送命令。

use GuzzleHttp\Promise; $sdk = new Aws\Sdk([ 'version' => 'latest', 'region' => 'us-west-2' ]); $s3 = $sdk->createS3(); $ddb = $sdk->createDynamoDb(); // Create a generator that yields promises $promiseGenerator = function () use ($s3, $ddb) { yield $s3->listBucketsAsync(); yield $ddb->listTablesAsync(); // yield other promises as needed... }; // Execute the tasks yielded by the generator concurrently while limiting the // maximum number of concurrent promises to 5 $promise = Promise\each_limit($promiseGenerator(), 5); // Waiting on an EachPromise will wait on the entire task queue to complete $promise->wait();

承諾協同程序

Guzzle promise 程式庫一個更強大的功能,是它允許您使用 promise coroutine,讓編寫非同步工作流看起來更像是編寫傳統的同步工作流。實際上,AWS SDK for PHP在大多數高層級抽象中使用 coroutine promise。

假設在儲存貯體可用時,您希望建立多個儲存貯體並上傳檔案到儲存貯體中,且想同時完成這些事,以便能夠盡快發生。您可以透過使用 all() promise 函數將多個 coroutine promise 組合在一起,輕鬆完成此任務。

use GuzzleHttp\Promise; $uploadFn = function ($bucket) use ($s3Client) { return Promise\coroutine(function () use ($bucket, $s3Client) { // You can capture the result by yielding inside of parens $result = (yield $s3Client->createBucket(['Bucket' => $bucket])); // Wait on the bucket to be available $waiter = $s3Client->getWaiter('BucketExists', ['Bucket' => $bucket]); // Wait until the bucket exists yield $waiter->promise(); // Upload a file to the bucket yield $s3Client->putObjectAsync([ 'Bucket' => $bucket, 'Key' => '_placeholder', 'Body' => 'Hi!' ]); }); }; // Create the following buckets $buckets = ['foo', 'baz', 'bar']; $promises = []; // Build an array of promises foreach ($buckets as $bucket) { $promises[] = $uploadFn($bucket); } // Aggregate the promises into a single "all" promise $aggregate = Promise\all($promises); // You can then() off of this promise or synchronously wait $aggregate->wait();