S3のあるバケットにファイルがアップされたら違うバケットにコピーしたいってことをしたいときに、
通常だったらcronで定期的にS3のあるバケット内を監視するなりなんなりが考えられるけど、
それってまぁあまりエコじゃなかったりとかそもそもそこまでする必要はないんじゃないかとか、
というかそもそもとあるバケットからとあるバケットにコピーする場面ってぶっちゃけあまりないよねとは思うけど。
けどまぁそこらへんをうまく解決するにはS3のイベント通知をSQSに向けてあげることで解決出来るかと。
ということで今日はその辺のお話をば。

■SQSのキューを作成

キュー名を適当に入力して後はデフォルト的な感じでキューの作成を行う。
※リージョンは普段自分が使っているリージョンにしておく
作成したキューにアクセス許可を追加する。

ちなみにアクションはSendMessageにチェックをする。
で、arn:aws:s3:::s3のバケット名とs3のbucket名を入れてアクセス許可の追加をする。
■S3のバケットにイベント通知を設定する

名前は適当で、イベントはput(更新)とpost(追加)の2種類を入れてあげる。
送信先をSQSキューとしてあげ、SQSキューのARN(SQSコンソールの詳細に書いてある)を入れてあげて保存。
■SQSのキューを見にいくプログラムの作成
namespace Fuel\Tasks;
require_once(APPPATH . "vendor/aws/aws-sdk-php/aws-autoloader.php");
use \Aws\Common\Aws;
use \Aws\Common\Enum\Region;
use Aws\DynamoDb\DynamoDbClient;
use Aws\Sqs\SqsClient;
class S3tasks{
public static function check_sqs(){
$time1 = time();
$client = SqsClient::factory(array(
"key" => "xxxxxxxxx",
"secret" => "xxxxxxxxx",
"region" => "ap-northeast-1"
));
while(true){
$queueUrl = $client->getQueueUrl(array(
'QueueName' => 'check-getstage-s3-upload'
));
$result = $client->receiveMessage(array(
'QueueUrl' => $queueUrl['QueueUrl'],
'MaxNumberOfMessages' => 1
));
$messages = $result->getPath('Messages/*/Body');
if(!empty($messages)){
foreach($messages as $message){
$data = json_decode($message);
if(isset($data->Records)){
foreach($data->Records as $d){
if(!preg_match("/^logs\/.+&/i",$d->s3->object->key)){
echo "{$d->s3->object->key}\tcopy item\n";
\S3::copy_object("移動元のパケット",$d->s3->object->key,"移動先のパケット",$d->s3->object->key,"public-read");
}
else{
echo "{$d->s3->object->key}\tnot copy item\n";
}
$client->deleteMessage(array(
'QueueUrl' => $queueUrl['QueueUrl'],
'ReceiptHandle' => $result->getPath('Messages/*/ReceiptHandle')[0]
));
}
}
}
}
else{
exit;
}
}
}
}
とりあえずこんな感じ。'MaxNumberOfMessages' => 1ってところで一回で引っ張ってくるキュー数を設定出来る。
ちなみにデフォルトは1。
自分としても一回一回処理が終わってキューの判定をしたいので、あえてここは1にしている。
S3にログがアップされたらこちらも通知されてしまうので、これを除外するためにpreg_matchしている。
\S3となっているのはfuelphpでS3に簡単にファイルをアップする仕組みを作る的なお話で紹介しているfuelphpのパッケージ。
受け取ったキューメッセージは削除したいので、deleteMessageを使って削除する必要あり。
で、これはwhile(true)で永続的に回しているけど、もちろんキューがない場合もあるわけで。
これを判断するためにif(!empty($messages))として、無かった場合にプログラムを削除するようにしている。
なのでcronでやってもプログラムが2重3重に走る事はないという感じ。
pull型なキューの取得になるけど、push型でやりたい場合はLambdaを使って一度Lambdaで何が変更されかたを取得し、
それでEC2というかあるURLに引数付きでアクセスするとコピー出来るようにするっていうのがあるんじゃないかと。
どちらにしろawsは色々と便利なものがあって使いこなすにはもちろん大変だし、
色々と設定しないといけないものがあって大変だけどいいんじゃないかと思ったり。
けど使いこなすことによって色々と便利になるからいいよ的なみたいな。
というか今回はなんか量も多いし、文章もかなり適当ではあるなぁと思った。
参考にしたサイト
S3 Event NotificasionsをAmazon SQSで受け取る - Glide Note - グライドノート
Amazon SQSを使った非同期処理の実装 ‹ ワンダープラネット株式会社(Wonderplanet Inc.)
Amazon Simple Queue Service(SQS)をPHPでいじる - Qiita
Amazon SQSを使ってみた② | Septeni Engineers' Blog | セプテーニ エンジニアブログ

0 件のコメント:
コメントを投稿