こちらはFrog Advent Calendar 2018の14日目の記事となります。
先月にAWS LambdaがRubyでかけるようになるとAmazonからアナウンスがあり、界隈で話題になっていたので早速手を動かしてみようということで。仕事でもすこーしだけLambdaで実装している部分があって、それはJavascriptで書いています。メインはAWS EC2で複数インスタンスを立ててその中でMicroservicesの形を取って複数のDockerインスタンスが各々Railsアプリを動かしています。で各サービス間はRESTでやりとりしたり、AWS SQS/SNSでサブスクリプションし合う形を取っています。その脇役として小さな処理をLambdaに任せている、ざっくり仕事のバックエンド環境はこのようになります。とりあえずバックエンドのみの説明だけ、backend developerとして働いているので。
さて、Lambdaとは何か、Amazonの公式サイトでは、
Run code without thinking about servers. Pay only for the compute time you consume.
とありますが、少し前にサーバーレスという言葉が流行ってた気がするのだけれど(最近そんな聞かない)、Lambdaはサーバーレスで、小さなアクション単位に作ることができる。RailsとかMVCなアーキテクチャーのフレームワークで例えると、コントローラーの中の1アクションをひとつのLambdaで表現できるイメージで僕はいます。
便利なものでLambdaの発動条件(トリガー)も様々から選べて、RESTで受けるAWS Gatewayから始まり、AWS S3に噛ませればファイルの更新をトリガーに走らせることでもできて、CloudWatach Eventでcronタスクでスケジューラーとしても走らせることができ、考えられることはなんでもできるといったところでしょうか。
それでは実際に触っていくのですが、すごーい簡単なもので何かないか、どうせ作るのなら何か欲しいものをと、考えていたら最近おしゃれなTattooを描くアーティストを見つけたことを思い出し、バンクーバーbasedの人なんですがInstagramのアカウントをちょくちょく見ていて、
こんなおしゃれならちょっとTattoo気になるぞということで、プロフィールの所にBooks reopen soon
とあったので、この予約不可から可に変わる時をいち早く知りたいなと、プロフィール欄を逐一確認するのは嫌だよねということでこのBooks reopen soon
が変わったことをお知らせしてくれる機能をLambdaでちょこっと作っていきます。
- インスタグラムのプロフィールページにアクセスして
Books reopen soon
の有無を確認(予約可になった時にこの文言が消えることを信じてw) - もしも予約可になっていたらSlack上でBotから自分宛にメッセージを送る
- これを定期的に繰り返す
というのをコードにすると、こうなりました。飾り気も何もない!
require 'net/http'
require 'json'
INSTA_URL = 'https://www.instagram.com/chinatown_stropky/'.freeze
SLACK_URL = 'https://slack.com/api/chat.postMessage'.freeze
def is_ready_to_book(event:, context:)
insta_uri = URI.parse(INSTA_URL)
insta_uri.query = URI.encode_www_form({ hl: 'en' })
https = Net::HTTP.new(insta_uri.host, insta_uri.port)
https.use_ssl = true
request = Net::HTTP::Get.new(insta_uri.request_uri)
response = https.request(request)
return true if response.body.include?('Books reopen soon')
slack_uri = URI.parse(SLACK_URL)
https = Net::HTTP.new(slack_uri.host, slack_uri.port)
https.use_ssl = true
header = {
'Content-Type' => 'application/json; charset=iso-8859-1',
'Authorization' => "Bearer #{ENV['SLACK_TOKEN']}"
}
request = Net::HTTP::Post.new(slack_uri.path, header)
request.body = {
channel: ENV['SLACK_CHANNEL'],
as_user: true,
text: "The status has changed! Go to #{INSTA_URL}"
}.to_json
https.request(request)
true
end
これをデプロイしていくわけですが、AWS CLIとAWS SAMを使っていきます。SAMは初めてだったんですが、いいですね、バージョンコントロールができて。仕事ではいまだにLambdaのちゃんとしたデプロイフローが確立できていないのがまずいところで、Lambda以外ではしっかりとあって、Terraformでベースを定義して、独自に作ったコマンドで日々のデプロイをしています。これらのツールはPythonが入ってれば普通にターミナルからコマンド叩いて導入できますね(以前に複数versionのPython入れようとしてなんやかんやしていたせいでSAMが動くようなるまで時間がかかりましたが)。AWS CLIは使う前にconfig設定してあげると使えるようなりますね。
流すコマンドは以下二つ、
sam package --template-file template.yml --s3-bucket bucket_name --output-template-file packaged.yaml
sam deploy --template-file ./packaged.yaml --stack-name stack_name --capabilities CAPABILITY_IAM --region us-east-1
ひとつ目がS3 bucketにコードをアップロードして、ふたつ目でLambdaにデプロイするコマンドですね。S3 bucketは事前に作っておく。 デプロイが完了したらAWS consoleで確認できるようなりました!
これで走らせるコードは用意できたので、次にトリガーを設定します。ここではCloudWatch Eventを使って10分ごとにコードが走るように設定していきます。
CloudWatchでcronタスクを設定するとこのように確認できました。
cron(0/10 * ? * * *)
これを作ったLambdaに設定してあげると完成ですね。
あとは寝て待つのみ、、
朝がきて、夜がきて、、
また朝がきて、時は経ち、、
キターー!!!のは来たんですが、実はご丁寧にもInstagramのstoryで告知してたのを先に見てしまっていたのでいつ変わるかを事前に知っていたという。。。
早足で駆け抜けましたが以上が初めてのLambda with Rubyでした。気がつけばバンクーバーに移り住んで3年になるようで、一瞬で時間が過ぎていきました。来年は節目、30歳になる年なのでしっかりNew Year’s resolutionを考えなければなと。。。いやでも本当真剣に。
良いお年を!
codeはここから