AWS SDK for PHP 버전 3의 커맨드 오브젝트 - AWS SDK for PHP

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

AWS SDK for PHP 버전 3의 커맨드 오브젝트

AWS SDK for PHP는 명령 패턴을 사용하여 나중에 HTTP 요청을 전송하는 데 사용될 파라미터와 핸들러를 캡슐화합니다.

명령의 암시적 사용

클라이언트 클래스를 검사하면 API 작업에 해당하는 메서드가 실제로 존재하지 않는 것을 확인할 수 있습니다. 이러한 메서드는 __call() magic 메서드를 사용하여 구현됩니다. 이러한 의사 메서드는 실제로 SDK의 명령 객체 사용을 캡슐화하는 바로 가기입니다.

일반적으로 명령 객체와 직접 상호 작용할 필요는 없습니다. Aws\S3\S3Client::putObject()와 같은 메서드를 호출하면 SDK는 제공된 파라미터를 기반으로 Aws\CommandInterface 객체를 실제로 생성하고, 명령을 실행한 다음, 채워진 Aws\ResultInterface 객체를 반환합니다(또는 예외나 오류 발생). 클라이언트의 Async 메서드 중 하나(예: Aws\S3\S3Client::putObjectAsync())를 호출하면 비슷한 워크플로가 수행됩니다. 클라이언트는 제공된 파라미터를 기반으로 명령을 생성하고, HTTP 요청을 직렬화한 다음, 요청을 시작하고, promise를 반환합니다.

다음은 기능적으로 동등한 예제입니다.

$s3Client = new Aws\S3\S3Client([ 'version' => '2006-03-01', 'region' => 'us-standard' ]); $params = [ 'Bucket' => 'foo', 'Key' => 'baz', 'Body' => 'bar' ]; // Using operation methods creates a command implicitly $result = $s3Client->putObject($params); // Using commands explicitly $command = $s3Client->getCommand('PutObject', $params); $result = $s3Client->execute($command);

명령 파라미터

모든 명령은 서비스의 API에 속하지 않지만 그 대신 SDK의 동작을 제어하는 몇 가지 특수 파라미터를 지원합니다.

@http

이 파라미터를 사용하여 기본 HTTP 핸들러가 요청을 실행하는 방식을 미세 조정할 수 있습니다. @http 파라미터에 포함시킬 수 있는 옵션은 "http" 클라이언트 옵션을 사용하여 클라이언트를 인스턴스화할 때 설정할 수 있는 옵션과 동일합니다.

// Configures the command to be delayed by 500 milliseconds $command['@http'] = [ 'delay' => 500, ];

@retries

"재시도" 클라이언트 옵션과 마찬가지로, @retries는 실패한 것으로 간주되기 전에 명령을 재시도할 수 있는 횟수를 제어합니다. 재시도를 비활성화하려면 이 옵션을 0으로 설정합니다.

// Disable retries $command['@retries'] = 0;
참고

클라이언트에서 재시도를 비활성화한 경우 해당 클라이언트에 전달된 개별 명령에서 재시도를 선택적으로 활성화할 수 없습니다.

명령 객체 생성

클라이언트의 getCommand() 메서드를 사용하여 명령을 생성할 수 있습니다. 이 명령은 HTTP 요청을 즉시 실행하거나 전송하지 않으며, 클라이언트의 execute() 메서드에 전달될 때만 실행됩니다. 따라서 명령을 실행하기 전에 명령 객체를 수정할 기회가 있습니다.

$command = $s3Client->getCommand('ListObjects'); $command['MaxKeys'] = 50; $command['Prefix'] = 'foo/baz/'; $result = $s3Client->execute($command); // You can also modify parameters $command = $s3Client->getCommand('ListObjects', [ 'MaxKeys' => 50, 'Prefix' => 'foo/baz/', ]); $command['MaxKeys'] = 100; $result = $s3Client->execute($command);

명령 HandlerList

클라이언트에서 명령을 생성한 경우 클라이언트 Aws\HandlerList 객체의 복제가 명령에 제공됩니다. 명령이 클라이언트에서 실행하는 다른 명령에 영향을 미치지 않는 사용자 지정 미들웨어와 핸들러를 사용할 수 있도록 클라이언트 핸들러 목록의 복제가 명령에 제공됩니다.

따라서 명령별로 다른 HTTP 클라이언트를 사용할 수 있으며(예: Aws\MockHandler) 미들웨어를 통해 명령별로 사용자 지정 동작을 추가할 수 있습니다. 다음 예제에서는 실제 HTTP 요청을 전송하는 대신 MockHandler를 사용하여 의사 결과를 생성합니다.

use Aws\Result; use Aws\MockHandler; // Create a mock handler $mock = new MockHandler(); // Enqueue a mock result to the handler $mock->append(new Result(['foo' => 'bar'])); // Create a "ListObjects" command $command = $s3Client->getCommand('ListObjects'); // Associate the mock handler with the command $command->getHandlerList()->setHandler($mock); // Executing the command will use the mock handler, which returns the // mocked result object $result = $client->execute($command); echo $result['foo']; // Outputs 'bar'

명령에 사용되는 핸들러를 변경할 수 있을 뿐 아니라, 사용자 지정 미들웨어를 명령에 주입할 수도 있습니다. 다음 예제에서는 핸들러 목록에서 관찰자로 작동하는 tap 미들웨어를 사용합니다.

use Aws\CommandInterface; use Aws\Middleware; use Psr\Http\Message\RequestInterface; $command = $s3Client->getCommand('ListObjects'); $list = $command->getHandlerList(); // Create a middleware that just dumps the command and request that is // about to be sent $middleware = Middleware::tap( function (CommandInterface $command, RequestInterface $request) { var_dump($command->toArray()); var_dump($request); } ); // Append the middleware to the "sign" step of the handler list. The sign // step is the last step before transferring an HTTP request. $list->append('sign', $middleware); // Now transfer the command and see the var_dump data $s3Client->execute($command);

CommandPool

Aws\CommandPool을 사용하면 Aws\CommandInterface 객체를 산출하는 반복자를 사용하여 명령을 동시에 실행할 수 있습니다. CommandPool은 풀의 명령을 반복하는 동안 일정한 수의 명령이 동시에 실행되도록 보장합니다(명령이 완료되면 일정한 풀 크기를 유지하기 위해 추가 명령이 실행됨).

다음은 CommandPool을 사용하여 몇 개의 명령만 전송하는 매우 간단한 예제입니다.

use Aws\S3\S3Client; use Aws\CommandPool; // Create the client $client = new S3Client([ 'region' => 'us-standard', 'version' => '2006-03-01' ]); $bucket = 'example'; $commands = [ $client->getCommand('HeadObject', ['Bucket' => $bucket, 'Key' => 'a']), $client->getCommand('HeadObject', ['Bucket' => $bucket, 'Key' => 'b']), $client->getCommand('HeadObject', ['Bucket' => $bucket, 'Key' => 'c']) ]; $pool = new CommandPool($client, $commands); // Initiate the pool transfers $promise = $pool->promise(); // Force the pool to complete synchronously $promise->wait();

이 예제는 CommandPool의 성능을 상당히 낮춘 것입니다. 더 복잡한 예제를 살펴보겠습니다. 디스크의 파일을 Amazon S3 버킷에 업로드한다고 가정합니다. 디스크에서 파일 목록을 가져오려면 PHP의 DirectoryIterator를 사용할 수 있습니다. 이 반복자는 SplFileInfo 객체를 생성합니다. CommandPoolAws\CommandInterface 객체를 산출하는 반복자를 받으므로, Aws\CommandInterface 객체를 반환하도록 SplFileInfo 객체를 매핑합니다.

<?php require 'vendor/autoload.php'; use Aws\Exception\AwsException; use Aws\S3\S3Client; use Aws\CommandPool; use Aws\CommandInterface; use Aws\ResultInterface; use GuzzleHttp\Promise\PromiseInterface; // Create the client $client = new S3Client([ 'region' => 'us-standard', 'version' => '2006-03-01' ]); $fromDir = '/path/to/dir'; $toBucket = 'my-bucket'; // Create an iterator that yields files from a directory $files = new DirectoryIterator($fromDir); // Create a generator that converts the SplFileInfo objects into // Aws\CommandInterface objects. This generator accepts the iterator that // yields files and the name of the bucket to upload the files to. $commandGenerator = function (\Iterator $files, $bucket) use ($client) { foreach ($files as $file) { // Skip "." and ".." files if ($file->isDot()) { continue; } $filename = $file->getPath() . '/' . $file->getFilename(); // Yield a command that is executed by the pool yield $client->getCommand('PutObject', [ 'Bucket' => $bucket, 'Key' => $file->getBaseName(), 'Body' => fopen($filename, 'r') ]); } }; // Now create the generator using the files iterator $commands = $commandGenerator($files, $toBucket); // Create a pool and provide an optional array of configuration $pool = new CommandPool($client, $commands, [ // Only send 5 files at a time (this is set to 25 by default) 'concurrency' => 5, // Invoke this function before executing each command 'before' => function (CommandInterface $cmd, $iterKey) { echo "About to send {$iterKey}: " . print_r($cmd->toArray(), true) . "\n"; }, // Invoke this function for each successful transfer 'fulfilled' => function ( ResultInterface $result, $iterKey, PromiseInterface $aggregatePromise ) { echo "Completed {$iterKey}: {$result}\n"; }, // Invoke this function for each failed transfer 'rejected' => function ( AwsException $reason, $iterKey, PromiseInterface $aggregatePromise ) { echo "Failed {$iterKey}: {$reason}\n"; }, ]); // Initiate the pool transfers $promise = $pool->promise(); // Force the pool to complete synchronously $promise->wait(); // Or you can chain the calls off of the pool $promise->then(function() { echo "Done\n"; });

CommandPool 구성

Aws\CommandPool 생성자는 다양한 구성 옵션을 받습니다.

concurrency (callable|int)

동시에 실행할 최대 명령 수입니다. 동적으로 풀 크기를 조정하려면 함수를 제공합니다. 함수에는 현재 보류 중인 요청 수가 제공되며 이 함수는 새 풀 크기 한도를 나타내는 정수를 반환할 것으로 예상됩니다.

before (callable)

각 명령을 전송하기 전에 호출할 함수입니다. before 함수는 명령과 명령의 반복자 키를 받습니다. 명령을 전송하기 전에 before 함수에서 필요에 따라 명령을 변형할 수 있습니다.

fulfilled (callable)

promise가 이행될 때 호출할 함수입니다. 결과 객체, 결과가 나온 반복자의 ID, 풀을 단락시켜야 하는 경우 해결하거나 거부할 수 있는 집계 promise가 함수에 제공됩니다.

rejected (callable)

promise가 거부될 때 호출할 함수입니다. Aws\Exception 객체, 예외가 나온 반복자의 ID, 풀을 단락시켜야 하는 경우 해결하거나 거부할 수 있는 집계 promise가 함수에 제공됩니다.

명령 간 수동 가비지 수집

대용량 명령 풀로 인해 메모리 제한에 도달한 경우에는 메모리 제한에 도달했을 때 PHP 가비지 수집기에서 수집된 순환 참조가 아닌, SDK에서 생성된 순환 참조가 원인일 수 있습니다. 이때는 명령 사이에 수집 알고리즘을 직접 호출하면 제한에 도달하기 전에 순환 참조를 수집할 수 있습니다. 다음 예제는 각 명령을 전송하기 전에 콜백을 사용해 수집 알고리즘을 호출하는 CommandPool을 생성하는 것입니다. 단, 가비지 수집기를 호출할 경우 성능 비용이 발생하므로 사용 사례와 환경에 따라 사용하는 것이 좋습니다.

$pool = new CommandPool($client, $commands, [ 'concurrency' => 25, 'before' => function (CommandInterface $cmd, $iterKey) { gc_collect_cycles(); } ]);