LoginSignup
54
51

More than 5 years have passed since last update.

Amazon LambdaでScala

Last updated at Posted at 2015-09-05

AWSのLambdaって、元々は、Node.jsベースの環境で、JavaScriptしか実行できませんでした。

つい先日ですが、Java8も実行できるようになりました。
http://aws.typepad.com/aws_japan/2015/06/aws-lambda-update-run-java-code-in-response-to-events.html

つまりそれって、JVMで実行できるってことですよね?じゃあScalaも動きますよね?
ってことで、やってみた。

コードは こちら

AWSでJava8を動かす方法

Scala云々の前に、まずはJavaでどーやるのか知っておかないとねってことで、主に、
https://docs.aws.amazon.com/ja_jp/lambda/latest/dg/java-lambda.html
を読みました。
ので、読んでね。

activator new

まずは、プロジェクトを作らないとねってことで、いつものこれを実行しました。

$ activator new                                                                                                                                                                                                       [~/workspace]

Fetching the latest list of templates...

Browse the list of templates: http://typesafe.com/activator/templates
Choose from these featured templates or enter a template name:
  1) minimal-akka-java-seed
  2) minimal-akka-scala-seed
  3) minimal-java
  4) minimal-scala
  5) play-java
  6) play-scala
(hit tab to see a list of all templates)
> 4
Enter a name for your application (just press enter for 'minimal-scala')
> aws-lambda-scala
OK, application "aws-lambda-scala" is being created using the "minimal-scala" template.

To run "aws-lambda-scala" from the command line, "cd aws-lambda-scala" then:
/home/vagrant/workspace/aws-lambda-scala/activator run

To run the test for "aws-lambda-scala" from the command line, "cd aws-lambda-scala" then:
/home/vagrant/workspace/aws-lambda-scala/activator test

To run the Activator UI for "aws-lambda-scala" from the command line, "cd aws-lambda-scala" then:
/home/vagrant/workspace/aws-lambda-scala/activator ui

これで、 aws-lambda-scala ってプロジェクトディレクトリができる。

activator eclipse with-source=true

次に、いま作ったプロジェクトをEclipseで扱えるようにしたい。

ちょっと前のactivatorならnewした時点で、eclipseプラグインが最初っから読み込まれていたんだけど、いまは自分で仕込む必要があるので、仕込む。

project/plugins.sbt
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0")

で、

$ ./activator                                                                                                                                                             
...
> eclipse with-source=true

みたいなことをすると必要なパッケージをとってきてくれるので、あとはEclipseで、既存プロジェクトをインポートする操作をしてやったらいい。

AWS SDK

Lambdaで動くよーにするために必要なLibraryを取得してくる。

けど、厳密にいうと、Lambdaで動かすだけなら、POJO でもいい。

が、S3のStreamで動かしたいとか、KinesisのStreamで動かしたいとか、そういったときにそれらからデータを取得してくるのに、SDKがあると便利だよねってことで使うことがあるから、一応、取ってくる。

build.sbt
val Version = "0.1-SNAPSHOT"

lazy val root = (project in file(".")).settings(
  name := "aws-lambda-scala",
  version := Version,
  organization := "com.example",
  scalaVersion := "2.11.7",
  libraryDependencies ++= Seq(
    "com.amazonaws" % "aws-lambda-java-core" % "1.0.0",
    "com.amazonaws" % "aws-lambda-java-events" % "1.1.0",
    "org.specs2" %% "specs2-core" % "3.6" % "test",
    "org.specs2" %% "specs2-mock" % "3.6" % "test",
    "org.specs2" %% "specs2-junit" % "3.6" % "test"
  ),
  assemblyJarName in assembly := "aws-lambda-scala-%s.jar" format(Version)
)

なんか色々書いたけど、必要なのは、 aws-lambda-java-coreaws-lambda-java-events のとこっすね。

assembly

LambdaにJavaのコードを実行させるには、オールインのJarを作る必要がある。

sbtのプラグインで、それするのに便利なプラグインがあるから、それも取ってくる。

project/plugins.sbt
addSbtPlugin("com.typesafe.sbteclipse" % "sbteclipse-plugin" % "4.0.0")

addSbtPlugin("com.eed3si9n" % "sbt-assembly" % "0.13.0")

さっきのEclipseのしたに sbt-assembly ってやつを追記した。

ちなみに、 plugins.sbt は改行を1つ多めにはさんであげないとコードの区切りを認識しないから一行あけてね。
0.13.7以降でなくなったとのこと。コメありがとうございます!!

Scala

で、やっとこコード。

src/main/scala/com/example/Hello.scala
package com.example

import scala.collection.JavaConverters._
import com.amazonaws.services.lambda.runtime.Context

trait HelloBase {

  def hello(myCount: Int, context: Context): java.util.List[String] = {
    println("Hello World!!")
    List("%d".format(myCount)).asJava
  }
}

class Hello extends HelloBase

こんな感じ。

このコードで大事なのは、

  1. helloメソッドの第一引数に、Lambda実行時のインプットを受け取るパラメータを用意する
  2. helloメソッドの第二引数に、 com.amazonaws.services.lambda.runtime.Context を受け取る
  3. 返り値の型を、 java.util.Listjava.uti.Map を指定する

ってとこで、それ以外は、好きにしていいみたい。

ちなみに、POJOでやるなら、

import scala.collection.JavaConverters._

class Hello {
  def hello(input: Any, context: Any): java.util.List[String] = {
    List("1","2","3").asJava
  }
}

って感じでもいけるはず。

activator assembly

コードも出来たし、Jarファイルを出力します。

$ ./activator assembly

って実行すると、 target/scala-2.11/aws-lambda-scala-0.1-SNAPSHOT.jar ってjarが出来ているはず!

Lambdaにfunctionを作成

コンソールでやってもいいけど、どうせならAWS CLI使いたいよねってことで、以下のコマンドを実行して、Lambda上に新しいFunctionを作る。

$ aws lambda create-function \
 --region us-east-1 \
 --function-name aws-lambda-scala \
 --zip-file fileb://aws-lambda-scala-0.1-SNAPSHOT.jar \
 --role arn:aws:iam::(AWSアカウントID):role/lambda_basic_execution \
 --handler com.example.Hello::hello \
 --runtime java8 \
 --timeout 15 \
 --memory-size 512

これ実行すると、

{
    "FunctionName": "aws-lambda-scala",
    "CodeSize": 12342769,
    "MemorySize": 512,
    "FunctionArn": "arn:aws:lambda:(リージョン):(AWSアカウントID):function:aws-lambda-scala",
    "Handler": "com.example.Hello::hello",
    "Role": "arn:aws:iam::(AWSアカウントID):role/lambda_basic_execution",
    "Timeout": 15,
    "LastModified": "2015-09-02T10:12:17.691+0000",
    "Runtime": "java8",
    "Description": ""
}

って結果が返ってくる。
これで出来た。

Lambda Invoke!!

じゃ実行してみよう!

$ aws lambda invoke \
 --region us-east-1 \
 --function-name aws-lambda-scala \
 --payload 123 \
 --invocation-type RequestResponse /tmp/response

で、

{
    "StatusCode": 200
}

って返ってきた!
成功したっぽいぞ。

invokeの結果を /tmp/response に吐き出したので、そっちを開いて確認してみる。

["123"]

ってなってる! payload で渡した 123 が List[String] になってJson化されて返ってきた!

まとめ

ScalaのSpecsテストが使えるから、単体テストもやりたい放題だぞ。

以上。

54
51
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
54
51