AWS SDK for PHP 버전 3에서의 Promise - AWS SDK for PHP

기계 번역으로 제공되는 번역입니다. 제공된 번역과 원본 영어의 내용이 상충하는 경우에는 영어 버전이 우선합니다.

AWS SDK for PHP 버전 3에서의 Promise

AWS SDK for PHP는 promise를 사용하여 비동기 워크플로를 허용하며, 이 비동기성 덕분에 HTTP 요청을 동시에 전송할 수 있습니다. SDK에서 사용하는 promise 사양은 Promises/A+입니다.

Promise란 무엇입니까?

promise는 비동기 작업의 최종 결과를 나타냅니다. promise와 상호 작용하는 기본 방법은 then 메서드를 통하는 것입니다. 이 메서드는 promise의 최종 값 또는 promise를 이행할 수 없는 이유를 수신할 콜백을 등록합니다.

AWS SDK for PHP는 promise 구현을 위해 guzzlehttp/promises Composer 패키지를 이용합니다. Guzzle promise는 차단 및 비차단을 지원하며 비차단 이벤트 루프와 함께 사용할 수 있습니다.

참고

HTTP 요청은 단일 스레드를 사용하여 AWS SDK for PHP에서 동시에 전송됩니다. 이 경우 상태 변경(예: promise 이행 또는 거부)에 응답하면서 하나 이상의 HTTP 요청을 전송하기 위해 비차단 호출이 사용됩니다.

SDK의 Promise

Promise는 SDK 전체에서 사용됩니다. 예를 들어, promise는 페이지네이터, 대기자, 명령 풀, 멀티파트 업로드, S3 디렉터리/버킷 전송 등과 같이 SDK에서 제공하는 대부분의 상위 수준 추상화에서 사용됩니다.

Async 접미사가 있는 메서드를 호출하면 SDK가 제공하는 모든 클라이언트는 promise를 반환합니다. 예를 들어, 다음 코드는 Amazon DynamoDBDescribeTable 작업의 결과를 가져오기 위해 promise를 생성하는 방법을 보여 줍니다.

$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']);

describeTable 또는 describeTableAsync를 호출할 수 있습니다. 이러한 메서드는 클라이언트와 연결된 API 모델 및 __call 번호로 구동되는 클라이언트의 magic version 메서드입니다. describeTable 접미사 없이 Async과 같은 메서드를 호출하면 클라이언트는 HTTP 요청을 전송하는 동안 차단하며 Aws\ResultInterface 객체를 반환하거나 Aws\Exception\AwsException을 발생시킵니다. 작업 이름에 Async(예: describeTableAsync) 접미사를 붙이면 클라이언트는 결국 Aws\ResultInterface 객체를 통해 이행되거나 Aws\Exception\AwsException을 통해 거부되는 promise를 생성합니다.

중요

promise가 반환될 때 결과가 이미 도착했거나(예: 모의(mock) 핸들러 사용 시) HTTP 요청이 시작되지 않았을 수 있습니다.

then 메서드를 사용하여 콜백을 promise에 등록할 수 있습니다. 이 메서드는 모두 선택적인 $onFulfilled$onRejected라는 두 개의 콜백을 받습니다. $onFulfilled 콜백은 promise가 이행되는 경우에 호출되고 $onRejected 콜백은 promise가 거부되는 경우(즉 실패한 경우)에 호출됩니다.

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

동시에 명령 실행

여러 개의 promise를 동시에 실행하도록 함께 작성할 수 있습니다. SDK를 비차단 이벤트 루프와 통합하거나 여러 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의 가장 좋은 측면 중 하나는 작성 가능하기 때문에 변환 파이프라인을 생성할 수 있다는 것입니다. 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 인수입니다. 다운스트림 promise 체인에 값을 제공하려는 경우 콜백 함수에서 값을 반환해야 합니다.

거부 전송

promise가 거부될 때 호출할 콜백을 등록합니다. 콜백에서 예외가 발생하면 promise가 예외를 통해 거부되고 체인의 다음 promise가 예외를 통해 거부됩니다. $onRejected 콜백에서 값을 성공적으로 반환하면 $onRejected 콜백의 반환 값을 사용하여 promise 체인의 다음 promise가 이행됩니다.

Promise 대기

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를 호출하면 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 취소

promise의 cancel() 메서드를 사용하여 promise를 취소할 수 있습니다. promise가 이미 해결된 경우 cancel()을 호출해도 효과가 없습니다. 한 promise를 취소하면 해당 promise와 해당 promise에서 전달을 대기하고 있는 모든 promise가 취소됩니다. 취소된 promise는 GuzzleHttp\Promise\RejectionException을 통해 거부됩니다.

Promise 결합

promise를 집계 promise로 결합하여 더욱 정교한 워크플로를 빌드할 수 있습니다. guzzlehttp/promise 패키지에는 promise를 결합하는 데 사용할 수 있는 다양한 함수가 포함되어 있습니다.

namespace-GuzzleHttp.Promise에서 모든 promise 컬렉션 함수에 대한 API 설명서를 참조할 수 있습니다.

each 및 each_limit

고정된 풀 크기로 동시에 수행할 Aws\CommandInterface 명령이 포함된 작업 대기열이 있는 경우 CommandPool을 사용하세요(명령은 메모리에 있거나 지연 반복기에 의해 생성될 수 있음). 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();

Promise 코루틴

Guzzle promise 라이브러리의 더욱 강력한 기능 중 하나는 비동기 워크플로 쓰기를 기존 방식의 동기 워크플로 쓰기와 비슷하게 만드는 promise 코루틴을 사용할 수 있다는 것입니다. 실제로 AWS SDK for PHP는 대부분의 상위 수준 추상화에서 코루틴 promise를 사용합니다.

여러 개의 버킷을 생성하고 버킷이 사용 가능하게 되면 버킷에 파일을 업로드하려고 하며, 이 모든 작업이 최대한 빠르게 수행되도록 모두 동시에 수행하려는 경우를 가정해 봅니다. all() promise 함수를 사용하여 여러 개의 코루틴 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();