Rails経由でAWS Lambda(ruby)を使いファイルをs3にアップロードする方法
タイトルが渋滞していますが、、やったことは下記のこと。
- Railsが非同期ジョブ走らせる
- 非同期ジョブはlambdaをinvokeする
- lambdaがcurlでファイルを持ってきて、s3にアップロードする
- その結果のアップロード先URLをRailsのDBに保存
AWS Lambdaを触ったのは初めてです。nodeではなくrubyで動かします。まずは、AWS上にLambda関数を作ります。今回は、コードは短いだろうと予想し、ローカルにインストールせずにAWSのWEB UIのエディタを使いました。
Role 追加
登場ロールは2つ、Rails側でlambdaをinvokeするロールとlambda関数を走らせるロール
Rails側でlambdaをinvokeするロール
*全部必要ではないかもしれませんが、面倒なので全て権限をあげました。
lambda関数を走らせるロール
Rails側のコード
AWS Ruby SDK version2 です。RequestResponseだと同期で処理します。返り値を拾うためにもここは同期で処理。invoke_copy自体を非同期で走らせるイメージです。
def invoke_copy(recording_id, download_url, object_path) req_payload = { download_url: download_url, object_path: object_path, } payload = JSON.generate(req_payload) resp = lambda.invoke({ function_name: "copyToS3", # required invocation_type: "RequestResponse", # accepts Event, RequestResponse, DryRun log_type: "Tail", # accepts None, Tail payload: payload, }) logger.debug Base64.decode64(resp.log_result) res = JSON.parse(resp["payload"].read()); logger.debug res self.update(url: res["body"]) end def lambda @lambda ||= Aws::Lambda::Client.new( region: "ap-northeast-1", access_key_id: ENV['AWS_ACCESS_KEY_ID'], secret_access_key: ENV['AWS_SECRET_KEY'] ) end
Lambda関数のコード
AWS Ruby SDK version3です。Lambdaの/tmpのみがwritableな場所で、maxで512MBです。 したがって、これ以上コピーできません。
require 'json' require 'aws-sdk-s3' def lambda_handler(event:, context:) puts event pp ENV puts `curl -L #{event["download_url"]} -o /tmp/a` puts `ls -al /tmp/a` puts `file /tmp/a` s3 = Aws::S3::Resource.new obj = s3.bucket('my-backet').object(event["object_path"]) obj.upload_file('/tmp/a') { statusCode: 200, body: obj.public_url } end
herokuでone-off dynoを利用してバッチを走らせる方法
rakeタスクを作らないで単純にメソッドを走らせたい、そしてメモリをたくさん使うアプリなのでsizeを変えてrails runner
$ heroku run:detached --size=standard-2x bundle exec rails runner Tasks::SomeTask.execute --app myapp
[AWS]リージョン間でkeypairをコピーする方法
Private keyからPublic keyを生成してそれをimportする。CLIでimportする方法もあるけど、リージョン数は10つぐらいなので手動で。
ssh-keygen -y -f wazaterm.pem > wazaterm.pub
[Linux] シンプルなプロセス監視にはimmortalが便利
プロセスがなにかの理由で死んだら、単純にリスタートさせたい。けど、systemdとかmonitとかの設定ファイルを書くのが面倒だなって思っていて調べていた。シェル(Bash)でLoopでかけそうだけど、
until myserver; do echo "Server 'myserver' crashed with exit code $?. Respawning.." >&2 sleep 1 done
Ref: Stackoverflow
これも面倒だと思ってしまいました。スクリプトの前にone command置く感じでやりたいなって調べてみると、immortalというツールを発見!早速インストール。
$ curl -s https://packagecloud.io/install/repositories/immortal/immortal/script.deb.sh | sudo bash $ sudo apt-get install immortal
使い方もシンプルで
$ immortal /bin/sh -c "sleep 5 && date > /tmp/sleep.log"
付属のimmortalctlで、管理できる。
$ immortalctl PID Up Down Name CMD 22400 4.6s 22364 /bin/sh -c sleep 5 && date > /tmp/sleep.log $ immortalctl halt 22364