yoskhdia’s diary

DDDとかプログラミングとかアーキテクチャとか雑多に

squbs探訪 その2(簡単なWebアプリケーションをつくってみる)

yoskhdia.hatenablog.com

の続きです。 ごく簡単なWebアプリケーションを作成して、どれだけAkkaに近いかを見ていきましょう。

Activatorテンプレートが公開されているので、基本はこれを参考にすれば良いですが、折角なのでAkka HTTP + Akka Streamsを使う場合の実装を試してみます。 なお、このエントリではScala 2.11.8で書いていますが、squbsではJavaのサンプルも公開されています。*1 AkkaはJava APIも持ちますので、Javaでも有用かもしれません。*2

注意:現在最新バージョンの0.8.1をベースにしています。0.9.0のマイルストーンが作業中であり、このなかではScala2.12対応やAkka HTTPの正式化が含まれるため、以下のコードがすぐに陳腐化する可能性があります。*3

build.sbt

依存性の設定と、ブートストラップの設定を行います。*4

val squbsVersion = "0.8.1"
libraryDependencies ++= Seq(
    "org.squbs" %% "squbs-unicomplex"   % squbsVersion,
    "org.squbs" %% "squbs-actormonitor" % squbsVersion,
    "org.squbs" %% "squbs-admin-exp"    % squbsVersion
)

mainClass in (Compile, run) := Some("org.squbs.unicomplex.Bootstrap")

最小限のものはsqubs-unicomplexと呼ばれるものだけです。 今回は、モニタリングに関してJMXが簡単に取得できるところも見てみるためsqubs-actormonitorsqubs-admin-exp*5を追加しています。*6

Akka HTTPの有効化

バージョン0.8.1時点では、Akka HTTPはExperimentalな機能です。 Akka HTTPで動作するように変更するには、以下の一行をapplication.confに追記します。

squbs.experimental-mode-on = true

アプリケーションサービス

次に、アプリケーションサービスを作っていきましょう。 squbsではエントリポイントとなるものをサービスと呼ぶようです。*7 Akka HTTPからAkka Streamsに繋げるところは公式ドキュメントを参考にしています。

package sample.squbs.api

import akka.http.scaladsl.model.{ ContentTypes, HttpEntity }
import akka.http.scaladsl.server.Route
import akka.stream.scaladsl.Source
import akka.util.ByteString
import org.squbs.unicomplex.streaming.RouteDefinition

import scala.util.Random

class HelloService extends RouteDefinition {

  val numbers = Source.fromIterator(() =>
    Iterator.fill(10)(Random.nextInt()))

  override val route: Route = {
    path("hello") {
      get {
        complete(HttpEntity(
          ContentTypes.`text/plain(UTF-8)`,
          numbers.map(n => ByteString(s"$n\n"))
        ))
      }
    }
  }
}

簡単ですね。 squbsが出てくるのは、RouteDefinitionをextendsしているところだけです。 あとはakka.http.scaladsl.server.Routeをどう構築するかだけなので、ここからはAkka HTTPの世界です。 この例では、Source[ByteString, Any]をとるHttpEntityをレスポンスとしています。

なお、ここではorg.squbs.unicomplex.streaming.RouteDefinitionを使っています。 他にもorg.squbs.unicomplex.RouteDefinitionがあり紛らわしいですが、このクラスはSpray版です。 次リリースの0.9.0では、ここは変わってくると思われます。

JSON, CSV, etc…

この例ではByteString直接にしましたが、JSONCSVは"Source Streaming · Akka HTTP“ページに説明のあるように任意のSource[T, _]の(Un)Marshallerを用意すれば比較的簡単です。 (Un)Marshallerの仕組みはAkka HTTPのそれですので、squbs独自に何か用意する必要はありません。

アプリケーションサービスの登録

上記で作成したアプリケーションサービスをsqubsに登録します。 squbsではActorヒエラルキーを構築し、これによってモニタリングなどの機能を組み込めるようになっています。 そのため、構成単位(squbsではCubeと呼んでいる)ごとにUnicomplexBootがアプリケーションサービスをActorとしてヒエラルキーに登録してアプリケーションが起動します。

サービスを登録するにはリソースディレクトリにMETA-INF/squbs-meta.confファイルを作成し、次のように記述します。

cube-name = sample.squbs.api

cube-version = "0.0.1-SNAPSHOT"
squbs-services = [
  {
    class-name = sample.squbs.api.HelloService
    web-context = ""
  }
]

ドキュメントにあるようにclass-nameweb-contextが基本となる設定です。 class-nameに作成したアプリケーションサービスのFQCNを指定します。 web-contextには例えばhttp://sample.com/v2/helloというURLであればv2部分に相当します。空文字の場合はルートからのパスとなります。

裏側ではClass.newInstanceで生成したアプリケーションサービス(=Definition)をActorが利用することで動いているようです。 そのため、アプリケーションサービスは現時点で引数のないコンストラクタが必須となっています。 DIなどは少し工夫が必要そうですね。

起動

sbt runとすればsqubsが起動します。 簡単ですね。

プロダクションで利用する場合はsbt-packagerやsbt-dockerなどを利用してパッケージングすると思いますが、まず試すぶんにはこれで十分でしょう。

JMX

squbs-actormonitorを依存性に追加している場合、squbsの管理するActorだけでなく作成したアプリケーションサービスのActorもJMXに登録されるようになります。 また、squbs-adminによって、JSON形式でJMX Beanを取得できるようになります。

http://localhost:8080/admにアクセスすると、登録されているJMX Beanが一覧で取得できます。

{
  "JMImplementation:type=MBeanServerDelegate" : "http://localhost:8080/adm/bean/JMImplementation:type~MBeanServerDelegate",
  "com.sun.management:type=DiagnosticCommand" : "http://localhost:8080/adm/bean/com.sun.management:type~DiagnosticCommand",
  "com.sun.management:type=HotSpotDiagnostic" : "http://localhost:8080/adm/bean/com.sun.management:type~HotSpotDiagnostic",
  ...
}

返ってきた一覧の各URLにアクセスすることで、それぞれのJMX Beanを取得できます。*8

感想

以上のとおり、ほとんどAkka APIになっているので、Akkaの知識をフルに使っていくことができそうです。 Akkaのドキュメントは良くできており、OSSでよくあるドキュメントが微妙に古かったり足りなかったり、ということもアプリケーションコードを書くなかでは起きにくいのもメリットですね。 squbsのドキュメントはMarkdownのものがGitにコミットされているくらいですが、頑張って書いている風に感じます。

プロダクションで使うならバージョン0.9.0からが丁度良いようにも思いますが、現0.8.1でも十分に使えるでしょう。 Akkaが中核にあり、squbsが担う部分は薄めに作られているためです。

次回は、他のコンポーネントにどんなものがあるか?や、アプリケーションアーキテクチャを考えてみるとどうなるか?あたりでひとつ? squbsが用意しているPatternコンポーネントもなかなか面白いので、どこかで紹介できたら良いですね。

*1:ただし、SBTやサービスの部分はScalaのまま

*2:誰か試してみて欲しい

*3:ええい、0.9.0リリースはまだか…!

*4:slf4jなどは省略してますので適宜調整してください。

*5:通常はsqubs-adminです。-expが付いているのはAkka HTTPはまだExperimentalサポートであるため別ライブラリになっているからです。

*6:他にもhttpclientなどがありますが、今回は割愛

*7:後述のsqubs-meta.confを見る限り。もう少し他の名前が良かったような…

*8:“org.squbs.unicomplex:type=ActorMonitor,name=user/admin"などいくつか404になるものがあるんですが、理由はまだわかってません…