RustでServerlessFrameworkを使ってみた

技術ネタ
この記事は約17分で読めます。

こんばんわ、hisayukiです

先週、初めて学生ハッカソンのサポートに参加させていただきました!
なんかいい感じに刺激になったので、自分のやりたいことやってみようと思います♪

ServerlessFrameworkが全然勉強進んでないのです。
ちょうどRustもやりたいところだったので、ServerlessFrameworkでやってみます!

スポンサーリンク

今回使ったもの

  • cargo 1.40.0-nightly
    • lambda_runtime v0.2.1
    • lambda_http v0.1.1
    • log v0.4

プロジェクト作成

前回、Rustのインストールまではやっているのでその辺りは省きます。

なので、早速プロジェクトを作成していきます!

cargo new ~/vscode/serverless-rust-sample

ServerlessFrameworkのインストール

package.jsonを作成してyarnでインストールします。
ここではyarnのインストール方法とかは省きます。

$ yarn init
yarn init v1.15.2
question name (serverless-rust-sample): 
question version (1.0.0): 
question description: 
question entry point (index.js): 
question repository url: 
question author (***** <*****@*******>): 
question license (MIT): 
question private: 
success Saved package.json
✨  Done in 10.70s.

こんな感じのpackage.jsonが出来上がります。

{
  "name": "serverless-rust-sample",
  "version": "1.0.0",
  "main": "index.js",
  "author": "***** <*****@*******>",
  "license": "MIT"
}

ここでServerlessFrameworkserverless-rustを追加

$ yarn add serverless@1.56.1
$ yarn add serverless-rust@0.3.6

追加後のpackage.jsonはこんな感じ

{
  "name": "serverless-rust-sample",
  "version": "1.0.0",
  "main": "index.js",
  "author": "",
  "license": "MIT",
  "dependencies": {
    "serverless": "1.56.1",
    "serverless-rust": "0.3.6"
  }
}

今回、rustのtemplateがないみたいなのでsls createコマンドは使いません。
なのでserverless.ymlを手書きします。

service: rust-sample
provider:
  name: aws
  runtime: rust
  memorySize: 128
  region: ap-northeast-1
plugins:
  - serverless-rust
package:
  individually: true
functions:
  rust-sample:
    handler: rust-sample
    events:
      - http:
          path: /
          method: GET

実行

デフォルトのコードを書き換えました。
そのままでもInvokeなどでLambdaとしては動かせるのですが、curlを使ってAPIGateway経由で動かなかったので・・・

use lambda_http::{lambda, IntoResponse, Request};
use lambda_runtime::{error::HandlerError, Context};
use serde_json::json;

fn main() {
    lambda!(handler)
}

fn handler(
    _: Request,
    _: Context,
) -> Result<impl IntoResponse, HandlerError> {
    Ok(json!({
        "message": "Go Serverless v1.0! Your function executed successfully!"
    }))
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn handler_handles() {
        let request = Request::default();
        let expected = json!({
            "message": "Go Serverless v1.0! Your function executed successfully!"
        })
        .into_response();
        let response = handler(request, Context::default())
            .expect("expected Ok(_) value")
            .into_response();
        assert_eq!(response.body(), expected.body())
    }
}

デフォルトとの違いとしてはlambda_httpを使ってます。
また、引数がデフォルトだとValuesですがRequestを使ってます。

ローカルテスト

$ yarn sls invoke local -f rust-sample
yarn run v1.15.2
$ /Users/*************/serverless-rust-sample/node_modules/.bin/sls invoke local -f rust-sample
Serverless: Building native Rust rust-sample func...
   Compiling rust-sample v0.1.0 (/code)
    Finished release [optimized] target(s) in 17.59s
  adding: bootstrap (deflated 61%)
Serverless: Packaging service...
Serverless: Building Docker image...
START RequestId: 6e3b851a-d6a7-1901-e5de-8d30cf4a4766 Version: $LATEST

END RequestId: 6e3b851a-d6a7-1901-e5de-8d30cf4a4766
REPORT RequestId: 6e3b851a-d6a7-1901-e5de-8d30cf4a4766  Init Duration: 50.26 ms Duration: 8.23 ms       Billed Duration: 100 ms Memory Size: 1536 MB    Max Memory Used: 10 MB
{
  "errorType": "Unhandled",
  "errorMessage": "JsonError: invalid type: string \"\", expected struct LambdaRequest at line 1 column 2"
}

 
 Exception -----------------------------------------------
 
  1
 
     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
 
  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com
 
  Your Environment Information ---------------------------
     Operating System:          darwin
     Node Version:              10.15.3
     Framework Version:         1.56.1
     Plugin Version:            3.2.1
     SDK Version:               2.2.0
     Components Core Version:   1.1.2
     Components CLI Version:    1.4.0
 
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

動かない・・・・

これ結局まだ理由わかってないです・・・w

"JsonError: invalid type: string \"\", expected struct LambdaRequest at line 1 column 2"

これが問題なのはわかるのですが、Rustの標準機能のテストだと通ってしまう。

$ cargo test
   Compiling rust-sample v0.1.0 (/Users/*************/serverless-rust-sample)
    Finished test [unoptimized + debuginfo] target(s) in 2.59s
     Running target/debug/deps/rust_sample-a9b79e2a2816bf2d

running 1 test
test tests::handler_handles ... ok

test result: ok. 1 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

ちなみにこのあとの実環境でも動いちゃいました💦

デプロイ&サーバー実行

ローカルでは動かなかったですが、AWS上にデプロイしてみます!

$ yarn sls deploy --aws-profile [プロファイル名]
yarn run v1.15.2
$ /Users/*************/serverless-rust-sample/node_modules/.bin/sls deploy --aws-profile [プロファイル名]
erverless: Building native Rust rust-sample func...
   Compiling rust-sample v0.1.0 (/code)
    Finished release [optimized] target(s) in 22.09s
  adding: bootstrap (deflated 61%)
Serverless: Packaging service...
Serverless: Creating Stack...
Serverless: Checking Stack create progress...
........
Serverless: Stack create finished...
Serverless: Uploading CloudFormation file to S3...
Serverless: Uploading artifacts...
Serverless: Uploading service rust-sample.zip file to S3 (1.07 MB)...
Serverless: Validating template...
Serverless: Updating Stack...
Serverless: Checking Stack update progress...
...........................
Serverless: Stack update finished...
Service Information
service: rust-sample
stage: dev
region: ap-northeast-1
stack: rust-sample-dev
resources: 10
api keys:
  None
endpoints:
  GET - https://d40rtxuc51.execute-api.ap-northeast-1.amazonaws.com/dev/
functions:
  rust-sample: rust-sample-dev-rust-sample
layers:
  None
Serverless: Run the "serverless" command to setup monitoring, troubleshooting and testing.
✨  Done in 111.97s.

デプロイ完了!コンソール開いてみます!

コンソール側でも確認できました!
というわけで、実際に動かしてみます!

$ yarn sls invoke -f rust-sample --aws-profile [プロファイル名]
yarn run v1.15.2
$ /Users/*************/serverless-rust-sample/node_modules/.bin/sls invoke -f rust-sample --aws-profile [プロファイル名]
{
    "errorMessage": "JsonError: missing field `path` at line 1 column 2",
    "errorType": "JsonError",
    "stackTrace": null
}
 
  Error --------------------------------------------------
 
  Error: Invoked function failed
      at AwsInvoke.log (/Users/*************/serverless-rust-sample/node_modules/serverless/lib/plugins/aws/invoke/index.js:105:31)
      at AwsInvoke.tryCatcher (/Users/*************/serverless-rust-sample/node_modules/bluebird/js/release/util.js:16:23)
      at Promise._settlePromiseFromHandler (/Users/*************/serverless-rust-sample/node_modules/bluebird/js/release/promise.js:547:31)
      at Promise._settlePromise (/Users/*************/serverless-rust-sample/node_modules/bluebird/js/release/promise.js:604:18)
      at Promise._settlePromise0 (/Users/*************/serverless-rust-sample/node_modules/bluebird/js/release/promise.js:649:10)
      at Promise._settlePromises (/Users/*************/serverless-rust-sample/node_modules/bluebird/js/release/promise.js:729:18)
      at _drainQueueStep (/Users/*************/serverless-rust-sample/node_modules/bluebird/js/release/async.js:93:12)
      at _drainQueue (/Users/*************/serverless-rust-sample/node_modules/bluebird/js/release/async.js:86:9)
      at Async._drainQueues (/Users/*************/serverless-rust-sample/node_modules/bluebird/js/release/async.js:102:5)
      at Immediate.Async.drainQueues [as _onImmediate] (/Users/*************/serverless-rust-sample/node_modules/bluebird/js/release/async.js:15:14)
      at runCallback (timers.js:705:18)
      at tryOnImmediate (timers.js:676:5)
      at processImmediate (timers.js:658:5)
      at process.topLevelDomainCallback (domain.js:120:23)
 
     For debugging logs, run again after setting the "SLS_DEBUG=*" environment variable.
 
  Get Support --------------------------------------------
     Docs:          docs.serverless.com
     Bugs:          github.com/serverless/serverless/issues
     Issues:        forum.serverless.com
 
  Your Environment Information ---------------------------
     Operating System:          darwin
     Node Version:              10.15.3
     Framework Version:         1.56.1
     Plugin Version:            3.2.1
     SDK Version:               2.2.0
     Components Core Version:   1.1.2
     Components CLI Version:    1.4.0
 
error Command failed with exit code 1.
info Visit https://yarnpkg.com/en/docs/cli/run for documentation about this command.

こっちも動かない・・・・

最後にcurlも試してみます。

$ curl -X GET "https://d40rtxuc51.execute-api.ap-northeast-1.amazonaws.com/dev/"
{"message":"Go Serverless v1.0! Your function executed successfully!"}

こっちは動いた(゜゜)

削除

$ yarn sls remove -f rust-sample --aws-profile [プロファイル名]
yarn run v1.15.2
$ /Users/*************/serverless-rust-sample/node_modules/.bin/sls remove -f rust-sample --aws-profile [プロファイル名]
Serverless: Getting all objects in S3 bucket...
Serverless: Removing objects in S3 bucket...
Serverless: Removing Stack...
Serverless: Checking Stack removal progress...
...................
Serverless: Stack removal finished...
✨  Done in 25.30s.

消すのはすんなり消えるので、やりたいこと終わったら消しちゃいましょうw

まとめ

API Gateway経由だとちゃんと動くけど、なぜかLambda単体では動かない・・・w
エラー見る限りではJSONにしたところでなんか問題が起きてるっぽいですが、まだ解明できてないです(´;ω;`)

実はこれの前にデフォルトの関数で作ったのですが、そっちはLambda単体では動くけどlambda_httpのライブラリ使わないのでAPI Gateway経由での動作が出来ませんでした💦

今日はここまでにして、少し調べてみようと思います!

参考サイト

RustとLambdaでなんか作る 前編 - Qiita
最近、カメネタばかりでしたがひと段落着いたので新ネタ行ってみましょう。で、最近気になってるのがRust.Rustって?wikipediaさんによるとこんな感じです。Rust(ラスト)はMoz…
Rustでのロギング - Qiita
Rustで使えるロガーを調べてみます。この記事ではいくつかある実装のうち、env_loggersimple_loggerstderrlogを動かしてみました。log crateRustの…

コメント