Scala入門記011 sbtでGoogle App Engine

ご無沙汰してます。
1年前から下書きにずっとあったのですが、内容は今も使ってる内容のままだったので投稿することにしました。

前回のServlet開発の延長線で、Google App EngineServletを動かす環境を作る設定を紹介したいと思います。
Scala入門記の目次はこちらです。


利用したライブラリ

今回はsbtプラグインの「sbt-appengine」を使いました。

github.com


前回紹介した「xsbt-web-plugin」のバージョン1.x系と使い方が似ています。


build.sbtの設定

name := "scala-sbt-appengine"

version := "1.0"

scalaVersion := "2.11.8"

libraryDependencies ++= Seq(
  "javax.servlet" % "servlet-api" % "2.5" % "provided",
  "org.eclipse.jetty" % "jetty-webapp" % "7.6.21.v20160908" % "container",
  "com.google.appengine" % "appengine-api-1.0-sdk" % "1.9.42",
  "com.google.appengine" % "appengine-api-stubs" % "1.9.42" % "test",
  "com.google.appengine" % "appengine-testing" % "1.9.42" % "test",
  "org.scalatest" %% "scalatest" % "2.2.6" % "test"
)

appengineSettings


コンテナとしてJettyを設定しています。
2016年9月の時点でもまだApp EngineはServlet2.5で動作するためJetty7を選択していますが、より新しいJettyを使っても動作するようです。
※参考ページ: https://wiki.eclipse.org/Jetty/Starting/Jetty_Version_Comparison_Table


project/plugins.sbtの設定

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

こちらがAppEngineを使うためのsbtプラグインです。
使い方はREADMEに詳しく載っていますが私がよく使うものは今回紹介します。


Servletのサンプル

package com.example

import java.util.Date
import javax.servlet.http.{HttpServlet, HttpServletRequest, HttpServletResponse}

class SampleServlet extends HttpServlet {

  override def doGet(request: HttpServletRequest, response: HttpServletResponse) = {

    val s = response.getOutputStream
    s.print("Hello! " + new Date().toString)
    s.flush()
  }
}

簡単なServletです。
前回とまったく同じです。


src/main/webapp/WEB-INF/web.xmlのサンプル

<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee"
         xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
         id="serv" version="3.0">

    <servlet>
        <servlet-name>SampleServlet</servlet-name>
        <servlet-class>com.example.SampleServlet</servlet-class>
    </servlet>

    <servlet-mapping>
        <servlet-name>SampleServlet</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

</web-app>

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>app-name</application>
    <version>app-version</version>
    <threadsafe>true</threadsafe>
</appengine-web-app>

App Engineで実行するための設定ファイルです。
https://appengine.google.comで作成したプロジェクトのIDと任意のバージョンを指定します。
これは実際にApp Engineへデプロイするまでは適当でOKですが、存在しないと開発サーバでも実行できません。


実行

sbt appengineDevServer

これで開発サーバが起動しますが、デフォルトでは8080で起動するため私はJenkinsとかぶってしまいます。

sbt "~appengineDevServer --port=8081"

このように--port=[ポート番号]と指定することで開発サーバが使うポートを変更することができます。
基本的に私は自分ではこのコマンドしか使わないです。
また、appengineDevServerでは毎回warを作る形ではありますがソースを更新すると開発サーバが再起動されすぐに動作を確認することも出来ます。


デプロイ

sbt "appengineDeploy"

このコマンドでAppEngineへデプロイ出来ます。

sbt "appengineDeploy --oauth2"

このように--oauth2オプションを付けることでOAuth認証が使えるので一度Google認証すると次回から認証画面を出さずにデプロイが可能です。
Jenkinsでデプロイするときなどに便利です。


まとめ

前回のServletをappengine-web.xmlを追加して設定を書き換えるだけでApp Engineにデプロイできるようになりました。
Mavenサポートが充実してきているようなのでsbtを使うメリットは少ないかもしれませんが、Scalaで書くならsbtで管理したいと思っています。


今回試した內容のソースはこちらです。
https://github.com/thachi/scala-sbt-appenginegithub.com


おまけ

今回作ったサンプルをApp Engineで実際に実行したところスピンアップは2.77秒でした。
f:id:t_hachinohe:20150819011504p:plain