S3にアップロードされたファイルをlambdaで別の場所に送信する
遅ればせながらなんだかスゴそうなlambdaを使ってみました。
lambdaでS3のイベントを受け取るには同一リージョンに作成する必要がありましたがlambdaは現在東京リージョンで使用可能です。
ですので以下は全てap-northeast-1リージョンに作成します。
まずS3のバケットを作成します。
この時点ではまだlambdaに関する設定はいりません。
次にlambda functionを作成します。
Select blueprintで言語をnode.jsとしてS3-get-objectを選択します。
次にイベントソースを設定します。Event source typeはS3、Bucketは先ほど作成したもの、Event typeはObject created(All)とします。
処理するファイルを限定する場合はPrefixにディレクトリ名、Suffixに拡張子を入れることで特定ディレクトリの特定拡張子のみに限定できます。
次に関数の設定をします。
以下のコードをインラインで登録します。名前は適当に。
npmのライブラリを使いたい場合はローカルでnpm installしてnode_modulesディレクトリと関数本体をまとめてzipで圧縮してアップロードします。(最上位にディレクトリが来ないように圧縮する必要がある)
※ちなみに一度ファイルをアップロードするともうインラインでの編集はできません。
console.log('Loading function'); var aws = require('aws-sdk'); var s3 = new aws.S3({ apiVersion: '2006-03-01' }); exports.handler = function(event, context) { console.log('Received event:', JSON.stringify(event, null, 2)); console.log('event', event); // Get the object from the event and show its content type var bucket = event.Records[0].s3.bucket.name; var key = decodeURIComponent(event.Records[0].s3.object.key.replace(/\+/g, ' ')); var params = { Bucket: bucket, Key: key }; s3.getObject(params, function(err, data) { if (err) { context.fail(err); } else { console.log('CONTENT TYPE:', data.ContentType); console.log('data', data); var paths = key.split('/'); var filePath = '/tmp/' + (new Date()).getTime() + '_' + paths[paths.length - 1]; require('fs').writeFileSync(filePath, data.Body); var file = require(filePath); console.log('file', file); var exec = require('child_process').exec; var cmd = "curl 'http://●●.●●.●●.●●:8983/solr/hoge/update?commit=true&indent=true' --data-binary @" + filePath; console.log('cmd', cmd); var child = exec(cmd, function(err, stdout, stderr) { if (err) { console.log('failed.', err); context.fail(err); } else { console.log('success.'); context.succeed(); } }); } }); };
Lambda function handler and roleのHandlerにはファイル名を入力する。hoge.jsファイルをアップロードした場合はhoge.handlerとする必要がある。
Roleは* S3 execution roleを選択すると権限の作成画面が出るのでそのまま許可とするとロールが作成される。
Memoryは128MB、Timeoutは1分とする。
Enable nowを選択すると次の画面でテストしろ的なメッセージが出ますがどうせテストなのでCreate functionします。
実際にS3にファイルをアップロードしてコードが実行されるか試してみます。
以下のjsonファイルを作成してコンソールからアップロードします。
# test.json [ "hoge": "hoge", "fuga": "fuga" ]
lambdaの該当ファンクションを選択しMonitoringタブを開いた右側にあるView logs in CloudWatchのリンクからCloudWatchのログを見ることができます。
ログストリームが作成されているはずなので中身を確認すると以下の様なログがあり、ファイル送信に成功していることが確認できました。
投げた先のsolrの方にもドキュメントが登録されていました。
lambda functionの注意点としては、ハンドラーでは最後にcontext.succeed();かcontext.fail();を実行して処理の完了を通知する必要があります。(context.fail();の場合は3回まで自動リトライ)
処理は非同期で実行されるのでファイル書き込み中やアップロード中でもcontext.succeed();を実行すれば処理はそこで終了してしまいます。
exports.handler = function(event, context) { ... var exec = require('child_process').exec; var cmd = "curl 'http://●●.●●.●●.●●:8983/solr/hoge/update?commit=true&indent=true' --data-binary @" + filePath; context.succeed(); // 上記のファイル送信処理の完了を待たずに処理が完了してしまう }
ですのでコールバックなどで処理結果を同期的に受け取ってcontext.succeed();をする必要があります。
その他詳細については↓のドキュメントを参照してください。
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/welcome.html
ひとまず以上です。lambdaたのC。
今回はnode.jsで実装しましたが非同期処理が前提なので結果は必ずコールバックで受け取らないといけない、というところを見落とすと落とし穴にハマりそうでした。(実際ちょっとハマりました)
複雑な非同期処理をする場合はasyncなどのライブラリを使うのが常套と言えそうです。
TAG
基本的にRuby on Railsで開発してます。最近はvue.jsも。好きな塔は円城です。
TAG
- Android
- AWS
- Bitrise
- CodePipeline
- Firebase
- HTML
- iOS
- IoT
- JavaScript
- KPI
- Linux
- Mac
- Memcached
- MGRe
- MGReのゆるガチエンジニアブログ
- MySQL
- PHP
- PICK UP
- PR
- Python
- Ruby
- Ruby on Rails
- SEO
- Swift
- TIPS
- UI/UX
- VirtualBox
- Wantedly
- Windows
- アクセス解析
- イベントレポート
- エンジニアブログ
- ガジェット
- カスタマーサクセス
- サーバ技術
- サービス
- セキュリティ
- セミナー・展示会
- テクノロジー
- デザイン
- プレスリリース
- マーケティング施策
- マネジメント
- ラボ
- リーンスタートアップ
- 企画
- 会社紹介
- 会社紹介資料
- 勉強会
- 実績紹介
- 拡張性
- 採用
- 日常
- 書籍紹介
- 歓迎会
- 社内イベント
- 社員インタビュー
- 社長ブログ
- 視察
- 開発環境