Promessas no AWS SDK for PHP Versão 3 - AWS SDK for PHP

As traduções são geradas por tradução automática. Em caso de conflito entre o conteúdo da tradução e da versão original em inglês, a versão em inglês prevalecerá.

Promessas no AWS SDK for PHP Versão 3

O AWS SDK for PHP usa promessas para permitir fluxos de trabalho assíncronos, e essa capacidade de assincronia permite que as solicitações HTTP sejam enviadas simultaneamente. A especificação da promessa usada pelo SDK é Promises/A+.

O que é uma promessa?

Uma promessa representa o resultado eventual de uma operação assíncrona. A principal maneira de interagir com uma promessa é por meio de seu método then. Esse método registra retornos de chamada para receber o valor eventual de uma promessa ou o motivo pelo qual a promessa não pode ser cumprida.

O AWS SDK for PHP depende do pacote do Composer guzzlehttp/promises para a implementação de suas promessas. As promessas do Guzzle oferecem suporte a fluxos de trabalho com e sem bloqueios e podem ser usadas com qualquer loop de eventos sem bloqueios.

nota

As solicitações HTTP são enviadas simultaneamente no AWS SDK for PHP usando um único thread, no qual as chamadas sem bloqueio são usadas para transferir uma ou mais solicitações HTTP e, ao mesmo tempo, reagir a alterações de estado (por exemplo, cumprindo ou rejeitando promessas).

Promessas no SDK

As promessas são usadas em todo o SDK. Por exemplo, as promessas são usadas na maioria das abstrações de alto nível fornecidas pelo SDK: paginadores, waiters, grupos de comandos, multipart uploads, transferências de diretórios/buckets do S3 e assim por diante.

Todos os clientes que o SDK fornece retornam promessas quando você chama qualquer um dos métodos com o sufixo Async. Por exemplo, o código a seguir mostra como criar uma promessa para obter os resultados de uma operação do Amazon DynamoDBDescribeTable.

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

Observe que você pode chamar describeTable ou describeTableAsync. Esses métodos são métodos __call mágicos em um cliente, que são acionados pelo modelo da API e pelo número da version associada ao cliente. Chamando métodos como describeTable sem o sufixo Async, o cliente será bloqueado ao enviar uma solicitação HTTP e retornar um objeto Aws\ResultInterface ou gerar uma Aws\Exception\AwsException. Com o uso do sufixo Async no nome da operação (isto é, describeTableAsync), o cliente criará uma promessa que será eventualmente cumprida com um objeto Aws\ResultInterface ou rejeitada com uma Aws\Exception\AwsException.

Importante

Quando a promessa é retornada, o resultado pode já ter chegado (por exemplo, ao usar um manipulador simulado) ou a solicitação HTTP pode não ter sido iniciada.

Você pode registrar um retorno de chamada com a promessa usando o método then. Esse método aceita dois retornos de chamada, $onFulfilled e $onRejected, que são opcionais. O retorno de chamada $onFulfilled será invocado se a promessa for cumprida, e o retorno de chamada $onRejected será invocado se a promessa for rejeitada (o que significa que falhou).

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

Execução simultânea de comandos

Várias promessas podem ser compostas em conjunto, para que sejam executadas simultaneamente. Isso pode ser obtido integrando o SDK com um loop de eventos sem bloqueio ou acumulando várias promessas e aguardando que sejam concluídas simultaneamente.

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());
nota

O CommandPool fornece um mecanismo mais poderoso para executar várias operações de API simultaneamente.

Encadeamento de promessas

Um dos melhores aspectos das promessas é que elas podem ser compostas permitindo que você crie pipelines de transformação. Promessas são compostas pelo encadeamento de retornos de chamada then com retornos de chamada then subsequentes. O valor do retorno de um método then é uma promessa que é cumprida ou rejeitada com base no resultado dos retornos de chamada fornecidos.

$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). } );
nota

O valor do retorno de chamada de uma promessa é o argumento $value que é fornecido para promessas de downstream. Para fornecer um valor para cadeias de promessas de downstream, você deve retornar um valor na função de retorno de chamada.

Encaminhamento de rejeição

Você pode registrar um retorno de chamada a ser invocado quando uma promessa for rejeitada. Se uma exceção for gerada em qualquer retorno de chamada, a promessa será rejeitada com a exceção, e as próximas promessas na cadeia serão rejeitadas com a exceção. Se você retornar um valor de um retorno de chamada $onRejected com êxito, as próximas promessas na cadeia de promessas serão cumpridas com o valor da chamada de retorno $onRejected.

Espera por promessas

Você pode forçar a conclusão de promessas de forma síncrona usando o método wait da promessa.

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

Se uma exceção for encontrada ao invocar a função wait de uma promessa, a promessa será rejeitada com a exceção, e a exceção será gerada.

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

Chamar wait em uma promessa que foi cumprida não aciona a função de espera. Ela simplesmente retorna o valor fornecido anteriormente.

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

Chamar wait em uma promessa que foi rejeitada gera uma exceção. Se o motivo da rejeição for uma instância de \Exception, o motivo será gerado. Caso contrário, uma GuzzleHttp\Promise\RejectionException será gerada e o motivo poderá ser obtido chamando o método getReason da exceção.

nota

As chamadas de operações da API no AWS SDK for PHP são rejeitadas com subclasses da classe Aws\Exception\AwsException. No entanto, é possível que o motivo fornecido a um método then seja diferente porque a adição de um middleware personalizado altera o motivo de uma rejeição.

Cancelamento de promessas

Promessas podem ser canceladas usando o método cancel() de uma promessa. Se uma promessa já tiver sido resolvida, a chamada de cancel() não terá nenhum efeito. O cancelamento de uma promessa cancela a promessa e todas as promessas que estão aguardando a entrega da promessa. Uma promessa cancelada é rejeitada com uma GuzzleHttp\Promise\RejectionException.

Combinação de promessas

Você pode combinar promessas em promessas agregadas para criar fluxos de trabalho mais sofisticados. O pacote guzzlehttp/promise contém várias funções que podem ser usadas para combinar promessas.

É possível encontrar a documentação da API de todas as funções da coleção de promessas em namespace-GuzzleHttp.Promise.

each e each_limit

Use o CommandPool quando tiver uma fila de tarefas de comandos Aws\CommandInterface para execução simultânea com um tamanho de grupo fixo (os comandos podem estar na memória ou serem gerados por um iterador lento). O CommandPool garante que um número fixo de comandos sejam enviados simultaneamente até que o iterador fornecido esteja esgotado.

O CommandPool funciona apenas com comandos que são executados pelo mesmo cliente. Você pode usar a função GuzzleHttp\Promise\each_limit para executar comandos de envio de diferentes clientes simultaneamente usando um tamanho de grupo fixo.

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();

Corrotinas de promessas

Um dos recursos mais avançados da biblioteca de promessas do Guzzle é que ela permite usar corrotinas de promessas que fazem a criação de fluxos de trabalho assíncronos parecer serem mais como a criação de fluxos de trabalho síncronos tradicionais. Na verdade, o AWS SDK for PHP usa promessas de corrotina na maioria das abstrações de alto nível.

Imagine que você quisesse criar vários buckets e fazer upload de um arquivo em um bucket quando o bucket se tornasse disponível, e quisesse fazer isso tudo simultaneamente para que ocorresse o mais rápido possível. Você pode fazer isso facilmente combinando várias promessas de corrotina em conjunto usando a função de promessa all().

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();