日頃の行い

個人的な日頃の行いをつらつら書いてます\\\\ ٩( 'ω' )و ////

localstack上でSQS->Lambda(Scala製)の連携を動かしてみる

開発時にlocalstackをAmazon Resourceのモックとして使っていて、
前試してなんか動かなかったんだけど、ちゃんとやったら動いたのでそのメモです。

github.com

localstack上のSQSにメッセージを送ったら、localstack上でmappingされたScala製のLambdaがキックされる様子を観測するのがゴールです。
検証用に使ったコードはこちらです。

github.com

登場するコマンドたちのversion

$aws --version
aws-cli/1.16.260 Python/3.7.4 Darwin/18.7.0 botocore/1.12.250

$docker-compose --version
docker-compose version 1.24.1, build 4667896b

1. localstackの起動

docker-composeを利用しつつlocalstackのSQSとLambdaを起動します。
利用したlocalstackのversionは 0.10.6 です。
networksは内部で別のコンテナと通信したいときに指定するために使います。
(実は今回は使ってないですごめんね)

docker-compose.yml

version: "2"

services:
    localstack:
        image: localstack/localstack:0.10.6
        ports:
          - "4567-4597:4567-4597"
        environment:
            LAMBDA_EXECUTOR: docker
            DOCKER_HOST: unix:///var/run/docker.sock
            DATA_DIR: /tmp/localstack/data
            SERVICES: sqs,lambda
            DEBUG: 1
            # 内部APIを叩きたいときなどに使う
            LAMBDA_DOCKER_NETWORK: localstack-sqs-lambda_foo_network
        volumes:
          - "/var/run/docker.sock:/var/run/docker.sock"
        networks:
            foo_network:

networks:
    foo_network:

2. Lambda Handlerの作成

特に強い意図はないのですが仕事で触れていたのがScalaだったのでScalaで書いています。
HelloWorldとメッセージに含まれるBodyを表示する感じです。

scala/src/main/scala/com/ru/waka/FooHandler.scala

package com.ru.waka

import com.amazonaws.services.lambda.runtime.{Context, RequestHandler}
import com.amazonaws.services.lambda.runtime.events.SQSEvent
import scala.collection.JavaConverters._

class FooHandler extends RequestHandler[SQSEvent, Unit] {
  override def handleRequest(input: SQSEvent, context: Context): Unit = {
    context.getLogger.log("Hello World from Scala Code\n")
    context.getLogger.log("Message's body is...\n")
    input.getRecords.asScala.foreach(r => {
      context.getLogger.log(s"${r.getBody}")
    })
  }
}

Lambdaにわたす際のビルドにはsbt-assemblyを利用しています。

github.com

ビルドの様子

$make -C scala build
# Lambdaのコードビルド
make[1]: Entering directory '/Users/arata/.ghq/github.com/ara-ta3/localstack-sqs-lambda/scala'
./tools/sbt/bin/sbt assembly
[info] Loading settings for project scala-build from build.sbt ...
[info] Loading project definition from /Users/arata/.ghq/github.com/ara-ta3/localstack-sqs-lambda/scala/project
[info] Loading settings for project scala from build.sbt ...
[info] Set current project to scala (in build file:/Users/arata/.ghq/github.com/ara-ta3/localstack-sqs-lambda/scala/)
[info] Strategy 'discard' was applied to 32 files (Run the task at debug level to see details)
[info] Strategy 'filterDistinctLines' was applied to a file (Run the task at debug level to see details)
[info] Assembly up to date: /Users/arata/.ghq/github.com/ara-ta3/localstack-sqs-lambda/scala/target/scala-2.12/scala-assembly-0.1.0-SNAPSHOT.jar
[success] Total time: 1 s, completed 2019/12/20 22:50:41
make[1]: Leaving directory '/Users/arata/.ghq/github.com/ara-ta3/localstack-sqs-lambda/scala'

3. SQSとLambdaの作成

次にlocalstack上にSQSとLambda、そしてそのマッピングを作成します。
Lambda作成時には 2. でビルドした成果物のjarファイルを上げています。

# SQSの作成
$aws --endpoint-url http://localhost:4576 \
    sqs create-queue --queue-name 'foo-queue'
{
    "QueueUrl": "http://localhost:4576/queue/foo-queue"
}

# Lambdaの作成
$aws --endpoint-url http://localhost:4574 \
    lambda create-function \
    --function-name 'foo-function' \
    --runtime=java8 \
    --role=dummyrole \
    --handler=com.ru.waka.FooHandler \
    --zip-file=fileb://./scala/target/scala-2.12/scala-assembly-0.1.0-SNAPSHOT.jar
{
    "FunctionName": "foo-function",
    "FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:foo-function",
    "Runtime": "java8",
    "Role": "dummyrole",
    "Handler": "com.ru.waka.FooHandler",
    "CodeSize": 10857096,
    "Description": "",
    "Timeout": 3,
    "LastModified": "2019-12-20T13:50:43.397+0000",
    "CodeSha256": "VJ4FGoNtdijTBO5acf/pu5WW/K/FQFytSH+x9WprcQc=",
    "Version": "$LATEST",
    "TracingConfig": {
        "Mode": "PassThrough"
    },
    "RevisionId": "fbaff8d2-6ac0-4498-879a-57b87cdd1466"
}

# SQSとLambdaのマッピング
$aws --endpoint-url http://localhost:4574 \
    lambda create-event-source-mapping \
    --event-source-arn arn:aws:sqs:us-east-1:000000000000:foo-queue  \
    --function-name "foo-function"
{
    "UUID": "b07dc12c-5a74-490b-82b4-1e43abdb6761",
    "BatchSize": 100,
    "EventSourceArn": "arn:aws:sqs:us-east-1:000000000000:foo-queue",
    "FunctionArn": "arn:aws:lambda:us-east-1:000000000000:function:foo-function",
    "LastModified": 1576849845.0,
    "LastProcessingResult": "OK",
    "State": "Enabled",
    "StateTransitionReason": "User action"
}

これでSQSにメッセージを送ればLambdaがキックされてHello Worldが表示されるはずです。

4. メッセージを送る

aws cliからメッセージを送ってみました。
そうするとdocker-composeのログにINFOログが流れてきたのがわかります。

$aws --region us-east-1 --endpoint-url http://localhost:4576 \
    sqs send-message \
    --queue-url 'http://localstack:4576/queue/foo-queue' \
    --message-body 'hogehoge'
{
    "MD5OfMessageBody": "329435e5e66be809a656af105f42401e",
    "MD5OfMessageAttributes": "d41d8cd98f00b204e9800998ecf8427e",
    "MessageId": "c3aa9a0c-9c3d-4b61-a426-9d45a2b2595f"
}

# docker-composeのログ
localstack_1  | 13:50:42.627 [elasticmq-akka.actor.default-dispatcher-4] INFO  o.elasticmq.actor.QueueManagerActor - Creating queue QueueData(foo-queue,MillisVisibilityTimeout(30000),PT0S,PT0S,2019-12-20T13:50:42.597Z,2019-12-20T13:50:42.597Z,None,false,false,None,None,Map())
localstack_1  | 2019-12-20T13:53:26:DEBUG:localstack.services.awslambda.lambda_api: Found 1 source mappings for event from SQS queue arn:aws:sqs:us-east-1:000000000000:foo-queue: ['arn:aws:lambda:us-east-1:000000000000:function:foo-function']
localstack_1  | 2019-12-20T13:53:26:DEBUG:localstack.services.awslambda.lambda_executors: Running lambda cmd: CONTAINER_ID="$(docker create -i  --entrypoint ""  -e DOCKER_LAMBDA_USE_STDIN="$DOCKER_LAMBDA_USE_STDIN" -e HOSTNAME="$HOSTNAME" -e LOCALSTACK_HOSTNAME="$LOCALSTACK_HOSTNAME" -e AWS_LAMBDA_FUNCTION_NAME="$AWS_LAMBDA_FUNCTION_NAME" -e AWS_LAMBDA_FUNCTION_VERSION="$AWS_LAMBDA_FUNCTION_VERSION" -e AWS_LAMBDA_FUNCTION_INVOKED_ARN="$AWS_LAMBDA_FUNCTION_INVOKED_ARN" --network="localstack-sqs-lambda_foo_network" --rm "lambci/lambda:java8" bash -c 'cd /var/task; java  -cp ".:localstack-utils-fat.jar" "cloud.localstack.LambdaExecutor" "com.ru.waka.FooHandler" "event_file.json"')";docker cp "/tmp/localstack/zipfile.2c9c80b9/." "$CONTAINER_ID:/var/task"; docker start -ai "$CONTAINER_ID";
localstack_1  | 2019-12-20T13:53:29:DEBUG:localstack.services.awslambda.lambda_executors: Lambda arn:aws:lambda:us-east-1:000000000000:function:foo-function result / log output:
localstack_1  | ()
localstack_1  | >Dec 20, 2019 1:53:28 PM cloud.localstack.LambdaContext$1 log
localstack_1  | > INFO: Hello World from Scala Code
localstack_1  | >
localstack_1  | > Dec 20, 2019 1:53:28 PM cloud.localstack.LambdaContext$1 log
localstack_1  | > INFO: Message's body is...
localstack_1  | >
localstack_1  | > Dec 20, 2019 1:53:28 PM cloud.localstack.LambdaContext$1 log
localstack_1  | > INFO: hogehoge

ハマったところ

aws cliからメッセージを送った際、Regionが $HOME/.aws/config に記述されているデフォルトのRegionを見ていて ap-northeast-1 になっていました。
しかし、アプリケーション(Java SDK)から叩いた際にRegionを ap-northeast-1 に指定しても利用されるSQSは us-east-1 になってしまいました。
そのため、上記では us-east-1 を利用するようにしています。
他の言語のSDKがどうなっているかはわからないですが、ローカルでの開発用途になると思いますし、localstackに対してaws cliで叩くときにregionのオプションをつければいいだけになるので us-east-1 でとりあえず逃げることはできそうですね。

Java SDKから叩いた際のコード

scala/src/main/scala/com/ru/waka/SQSMessageSender.scala

package com.ru.waka

import com.amazonaws.regions.Regions
import com.amazonaws.services.sqs.AmazonSQSClientBuilder
import com.amazonaws.services.sqs.model.SendMessageRequest

object SQSMessageSender {
  def main(args: Array[String]): Unit = {
    val sqs = AmazonSQSClientBuilder
      .standard()
      .withRegion(Regions.AP_NORTHEAST_1)
      .build()
    val req = new SendMessageRequest()
        .withQueueUrl("http://localhost:4576/queue/foo-queue")
        .withMessageBody("Message from Scala Code")
    sqs.sendMessage(req)
  }
}

scalikejdbcを使ってMySQLにクエリを投げるだけのメモ

久しぶりにScalaを触ってMySQLにクエリを投げたいだけなんだけど、
それすらもぱっとは思い出せなかったので備忘録として書いとこうと思います。

scalikedjbc

github.com

検証用レポジトリはこちら。
make run で多分動きます。

github.com

build.sbt

とりあえずおもむろにbuild.sbtにscalikejdbcを追加します。
3系出てたんですね。
長いこと触って無くて知りませんでした。

scalaVersion := "2.12.5"

libraryDependencies ++= Seq(
    "org.scalikejdbc" %% "scalikejdbc" % "3.2.3",
    "mysql" % "mysql-connector-java" % "6.0.6"
)

書いたコードは結局このくらいでした。
localTxの実装を見たらなにかあったらThrowableが投げられるみたいだったのでcatchingで囲むことにしました。
Throwableが投げられたとしても特に何もしなかったらrollbackされなかったので、
投げられたら(Leftが返ってきたら)rollbackするような実装にしました。

package com.ru.waka

import java.time.LocalDateTime

import scalikejdbc.{ConnectionPool, DBSession, NamedDB, SQL}

import scala.util.control.Exception._

object Hello {
  private val connectionSymbol = 'testDB

  Class.forName("com.mysql.cj.jdbc.Driver")

  ConnectionPool.add(connectionSymbol, "jdbc:mysql://localhost/test?characterEncoding=UTF-8", "root", "")

  val repository = new HelloRepository(connectionSymbol)

  def main(args: Array[String]): Unit = {
    val time = LocalDateTime.now().toString
    NamedDB(connectionSymbol) localTx {implicit  session =>
      (
        for {
          _ <- createTable()
          _ <- repository.put(time)
          rs <- repository.fetch()
        } yield rs) match {
        case Right(rs) =>
          session.connection.commit()
          println(rs)
        case Left(th) =>
          session.connection.rollback()
          println(th)
      }
    }
  }

  def createTable()(implicit session: DBSession): Either[Throwable, Boolean] = catching(classOf[Throwable]) either {
    SQL(
      """
        |CREATE TABLE IF NOT EXISTS foo (hello varchar(100))
      """.stripMargin
    ).execute().apply()
  }
}

class HelloRepository(connectionName: Symbol) {
  def put(hello: String)(implicit session: DBSession): Either[Throwable, Int] =
    catching(classOf[Throwable]) either
      SQL(
        """
          |INSERT INTO foo (hello) VALUES (?);
        """.stripMargin
      ).bind(hello).executeUpdate().apply()

  def fetch() (implicit session: DBSession): Either[Throwable, Seq[Map[String, Any]]] =
    catching(classOf[Throwable]) either
      SQL(
        """
          |SELECT hello FROM foo;
        """.stripMargin
      ).map(_.toMap()).list().apply()
}

scalikejdbc.SQLの引数にクエリを渡して、
executeしてapplyすればクエリが走りました。
めでたしめでたし。
implicit parameterってどう使われるのかの理解が浅かったのでこのあたりも参考に読みました。

参考

いちいちsessionを渡さなくてもいい感じに渡してくれるので便利ですね。
(暗黙なのちょっと不安だけど)

sbtを使ってGoogleAppEngineにScalaのコードで書いたアプリケーションをデプロイするの巻

GoogleAppEngine for Javaはありますが、JavaではなくScalaで書きたいので、Scalaでデプロイ出来ないかなと色々探してみました。

cloud.google.com

やること

やることは簡単です。

使ったもののVersionはScala 2.11.7, sbt 0.13.11 です。

1. sbt-appengine pluginの導入

こちらを利用します。

github.com

2ファイル用意する必要があります。
0.12.xの時は違う設定になるようなので注意です。

appengine.sbt

libraryDependencies += "org.mortbay.jetty" % "jetty" % "6.1.22" % "container"

appengineSettings

/project/plugins.sbt

addSbtPlugin("com.eed3si9n" % "sbt-appengine" % "0.6.2")

2. appengine-web.xmlの準備

/src/main/webapp/WEB-INF/appengine-web.xml

<?xml version="1.0" encoding="utf-8"?>
<appengine-web-app xmlns="http://appengine.google.com/ns/1.0">
    <application>dark</application>
    <version>1</version>
    <threadsafe>true</threadsafe>
</appengine-web-app>

ここでのapplicationはGoogle Console上の project id を指定します。

3. Servlet用のclassとweb.xmlの準備

/src/main/scala/com/ru/waka/servlets/Main.scala

package com.ru.waka.servlets

import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse}

class Main extends HttpServlet {
  override def doGet(request: HttpServletRequest, response: HttpServletResponse) {
    response.setContentType("text/plain")
    response.getWriter.println("Hello, world")
  }
}

/src/main/webapp/WEB-INF/web.xml

<?xml version="1.0" encoding="utf-8"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_2_5.xsd" version="2.5">
<servlet>
    <servlet-name>Main</servlet-name>
    <servlet-class>com.ru.waka.servlets.Main</servlet-class>
</servlet>
<servlet-mapping>
    <servlet-name>Main</servlet-name>
    <url-pattern>/*</url-pattern>
</servlet-mapping>
</web-app>

4. Google App Engine SDKのダウンロードとの設定

SDKをダウンロードして、APPENGINE_SDK_HOMEという環境変数を設定する必要があります。
ダウンロードはこちらで。

Download the Google App Engine SDK - App Engine — Google Cloud Platform

APPENGINE_SDK_HOMEをunzipした↑のディレクトリのパスに設定します。

export APPENGINE_SDK_HOME=/path/to/unzipped_google_app_engine_sdk

tips

  • intellijで起動時にAPPENGINE_SDK_HOMEが見えるようにする
    • APPENGINE_SDK_HOMEをintellijに設定ができず困りました
    • APPENGINE_SDK_HOMEを設定したターミナルで open /Applications/IntelliJ\ IDEA\ 14\ CE.app/ とやると開けます。

実行

$sbt
[info] Loading project definition from /path/to/scala-on-appengine/project
[info] Set current project to scala-on-appengine (in build file:/path/to/scala-on-appengine/)
# Local Server 起動
> appengineDevServer
[info] Compiling 1 Scala source to /path/scala-on-appengine/target/scala-2.11/classes...
[info] 'compiler-interface' not yet compiled for Scala 2.11.7. Compiling...
[info]   Compilation completed in 11.87 s
[info] Packaging /path/scala-on-appengine/target/scala-2.11/scala-on-appengine_2.11-0.1-SNAPSHOT.war ...
[info] Done packaging.
[info] Starting dev server in the background ...
objc[4157]: Class JavaLaunchHelper is implemented in both /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/bin/java and /Library/Java/JavaVirtualMachines/jdk1.8.0_45.jdk/Contents/Home/jre/lib/libinstrument.dylib. One of the two will be used. Which one is undefined.
[success] Total time: 21 s, completed 2016/03/26 16:13:25
Listening for transport dt_socket at address: 1044
> 3 26, 2016 4:13:29 午後 com.google.apphosting.utils.jetty.JettyLogger info
情報: Logging to JettyLogger(null) via com.google.apphosting.utils.jetty.JettyLogger
3 26, 2016 4:13:29 午後 com.google.apphosting.utils.jetty.JettyLogger info
情報: jetty-6.1.x
3 26, 2016 4:13:31 午後 com.google.apphosting.utils.jetty.JettyLogger info
情報: Started SelectChannelConnector@127.0.0.1:8080
3 26, 2016 4:13:31 午後 com.google.appengine.tools.development.AbstractModule startup
情報: Module instance default is running at http://localhost:8080/
3 26, 2016 4:13:31 午後 com.google.appengine.tools.development.AbstractModule startup
情報: The admin console is running at http://localhost:8080/_ah/admin
3 26, 2016 4:13:31 午後 com.google.appengine.tools.development.DevAppServerImpl doStart
情報: Dev App Server is now running

# Deploy
> appengineDeploy
appcfg.sh should ideally be run using Java 7 (also known as 1.7).

The java executable at /usr/bin/java reports:
java version "1.8.0_45"
Java(TM) SE Runtime Environment (build 1.8.0_45-b14)
Java HotSpot(TM) 64-Bit Server VM (build 25.45-b02, mixed mode)

Running a more recent version of Java can lead to apps that are apparently
correct but do not work when uploaded to App Engine.

You can download JDK 7 from:
  http://www.oracle.com/technetwork/java/javase/downloads/jdk7-downloads-1880260.html
Please enter code:

ここまで来るとこんな画面が出るので、ログインしてみましょう。

f:id:arata3da4:20160326163422p:plain

f:id:arata3da4:20160326163440p:plain

Please enter code:のところにモザイクがかかっている値を入れると次に進みます。

Please enter code: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Reading application configuration data...

#appengine-web.xmlに記載している applicationの値(app_id) が存在していないので、
# エラーが出てデプロイされていませんが、合っていればデプロイされます。
Beginning interaction for module default...
3 26, 2016 4:31:18 午後 com.google.appengine.tools.admin.AbstractServerConnection send1
警告: Error posting to URL: https://appengine.google.com/api/appversion/getresourcelimits?app_id=dark&version=1&
403 Forbidden
You do not have permission to modify this app (app_id=u'dark').
This is try #0
3 26, 2016 4:31:18 午後 com.google.appengine.tools.admin.AbstractServerConnection send1
警告: Error posting to URL: https://appengine.google.com/api/appversion/getresourcelimits?app_id=dark&version=1&
403 Forbidden
You do not have permission to modify this app (app_id=u'dark').
This is try #1
3 26, 2016 4:31:19 午後 com.google.appengine.tools.admin.AbstractServerConnection send1
警告: Error posting to URL: https://appengine.google.com/api/appversion/getresourcelimits?app_id=dark&version=1&
403 Forbidden
You do not have permission to modify this app (app_id=u'dark').
This is try #2
3 26, 2016 4:31:19 午後 com.google.appengine.tools.admin.AbstractServerConnection send1
警告: Error posting to URL: https://appengine.google.com/api/appversion/getresourcelimits?app_id=dark&version=1&
403 Forbidden
You do not have permission to modify this app (app_id=u'dark').
This is try #3

com.google.appengine.tools.admin.HttpIoException: Error posting to URL: https://appengine.google.com/api/appversion/getresourcelimits?app_id=dark&version=1&
403 Forbidden
You do not have permission to modify this app (app_id=u'dark').

Unable to update app: Error posting to URL: https://appengine.google.com/api/appversion/getresourcelimits?app_id=dark&version=1&
403 Forbidden
You do not have permission to modify this app (app_id=u'dark').

Please see the logs [/var/folders/3x/tr8_68tx29v9skp0lv76ljvc0000gn/T/appcfg1764707419651306170.log] for further information.

というところでした。ScalaでもGoogle App Engineは使えました。 今回試したレポジトリはこちらです。 git cloneと 4. Google App Engine SDKのダウンロードとの設定 だけで動くと思います。 github.com

参考

#ScalaMatsuri 2016 に参加してきました。

2016/01/30 ~ 31で行われたScalaMatsuriに行ってきました。

scalamatsuri.org

去年からしっかりScala触るようになったので、前回よりは内容がわかるようになった気がしました。
体調悪くて1日目の午後から行きました。
見逃してしまったのは、ニコ生で見ようかなと思います。

ScalaMatsuri 2016 1日目 メイントラック - 2016/01/30 09:40開始 - ニコニコ生放送

ScalaMatsuri 2016 2日目 メイントラック(アンカンファレンス) - 2016/01/31 10:00開始 - ニコニコ生放送

全講演が公開される予定らしいので、そっちで見なおしてもいいかなと思ったんですが、
さっさと見ないと多分なかなか見ないので早めにニコ生で見ようかと思ってます。

もらったノベルティグッズたち!

Scalaパズルは買ったものです)

f:id:arata3da4:20160131194714j:plain

講演

ちょくちょく休憩してたんですが、聞いた講演のメモとかから簡単にまとめてみました。
間違っていたら指摘いただけると幸いです。

1日目

ScalaコードはJVMでどのように表現されているのか

とても読み易いclassファイル開いてみるところから始まり、
読めない人のためのコマンド javap コマンドの紹介とjavapによって出力されるJVMの命令の説明が入りました。
元々JVMの命令は200ちょい(?)で初め出てから追加されたのが少ない(1個だったっけ・・・?調べよう)らしく、
初期設計からとても優秀だったようでした。
その説明後、javacとscalacでコンパイルした結果のclassの比較をしてどう表現されるのかという話でした。
scalacの方が出力するclassファイルが多く、Scalaコンパイラは少ない記述から多くの命令を出力しているという話でした。

あなたのScalaを爆速にする7つの方法

x1.inkenkun.com

EC2インスタンス上でsbt-jmhを利用して、ある7つのケースで処理のベンチマークを取った時の結果をクイズ形式で紹介されていました。
自分のクイズ結果は4/7(´・ω・`)
理由含めて完全にわかった奴はすごく嬉しくなりましたが、外した奴は悲しくなりました・・・でも楽しかったw
あ、これSICPでやったやつだ!とかなったりしてけど、中でArrayが使われてるとか知らなくて外したりしました(言い訳
あと正規表現は正直わからんかった。

The Zen of Akka

www.slideshare.net

Akka全く仕事で使ったこと無くて、なんとなく動かしたことあるくらいだったんですが、それでも聞いていてそういう使い方をするんだなぁみたいな気持ちになれました。
あと絵が好き。Akkaの禅がわかった気がします(雑
特に心に残っているのは、 BackoffSupervisorCluster Gossip Convergence
BackoffSupervisor は例えば、Actorが利用しているDBが死んだ時にどれくらいの時間を置いてリトライをするかという責務を担うもので、
Cluster Gossip Convergence は、クラスタ内の全てのノードの状態が観測し得るときに新規のノードがクラスタ内に参加できると理解しました。
障害時にどうなるという部分が考えられていてすごいなぁと思いました(小並感

2日目

2日目はアンカンファレンスで、 1日目の時点でTwitter上や会場のホワイトボードに貼られた案を元に参加者の人が発表するみたいな形式でした。
ちなみに、ホワイトボードにはこんなのもあったりしました

(phq・・・

ScalaとSparkによる日本語テキストマイニング

入門者向けということもあって、テキストマイニングの基礎の部分からでした。
Featureとは例えばメールにはfromとtoがあるが、そのfromのこと。
Labelとは予測したいもの(?)例えばメールであれば、スパムであるかスパムでないかということ。
Modelとは学習結果のこと。
などの説明から始まり、機械学習は基本的にFeature Engineeringだという話されてました。(前処理大変ですよね
形態素解析器としてはKuromojiやMecabがあるが、Kuromojiの方がMavenレポジトリで公開されているのもあり、Java Scalaのプロジェクトであればインストール容易とのこと。
その後、自分に来るメールのテキストを元に作業依頼なのか他のタスクなのかを判定するデモ(?)をされていました。
2時間前に始めたプログラムがまだ終わらず一部結果が見せられないと聞いて大変ですよね・・・って思いました。

Scala.js コンパイルパイプライン

Scala.jsのコンパイラの話でした。
Scalaのコードからどういう過程でJavaScriptになっていくのかという話でした。
めっちゃ面白かったんですが、知識と頭がついていきませんでした・・・
資料が見つかったらまた見たいと思います。

別の発表(LT)ですが、Scala.jsといえばこちらも興味深かったです。
UIと切り離したロジック部分をScala.jsで書くという方針と懇親会の時聞いて、完全にUIが存在しない部分のjsのコードのaltJsとしてScala.jsを利用するみたいな話をして、それならまだ行けるのかもしれないと思いました。

speakerdeck.com

昔こんな記事書いてから追ってなかったので追おうかなと思いました。
Vue.jsに入門しようと思ってScala.jsでVue.jsのサンプル書いてみた。 - 日頃の行い

Scalaエンジニアの年収w

(ちなみに左端は一番上は少なくとも海外の方で、基本的には言語が書いていない無効票に記載された金額でした。

感想

  • たのしかった!
  • モナドとかよくわかってないからといって色々避けてしまった
  • なので、FP in Scalaをちゃんと読み終えたい
  • Actorモデル(というかAkka)面白そう
  • 同時通訳めちゃくちゃすごかったです!おかげで英語の発表も臆すること無く聴きに行けました。
  • おつかれJavaでした!