Screaming Loud

日々是精進

Play2.4で非推奨のGlobalSettingをなくす

Play2.4で非推奨、かつPlay2.5ではなくなっているGlobalSettingの消し方を紹介します。
なかなか大変なので、ブログにまとめておきました。

Global.scalaで書いていたコード

Play2.3で書いていたGlobal.scalaのコードを記載します。

object Global extends WithFilters(CsrfFilter, AccessLoggingFilter, SystemAccessFilter) with GlobalSettings with JsonHelper {

  override def onStart(app: Application) {
    Akka.system.scheduler.schedule(1 hour, 1 hour) {
      Image.cleanTempImage()
    }
  }

  override def onError(request: RequestHeader, ex: Throwable): Future[Result] = {
    Logger.warn(s"Internal server error. Messages : ${e.getMessage} ExceptionMessage: ${e.getMessage()}")
  }
}

/**
 * アクセスログ出力フィルター
 */
object AccessLoggingFilter extends Filter {
  import models.component.RequestComponent._

  val accessLogger = Logger("access")
  def apply(next: (RequestHeader) => Future[Result])(request: RequestHeader): Future[Result] = {
    val resultFuture = next(request)
    val startTime = System.currentTimeMillis

    resultFuture.flatMap { result =>
      val takeTime = System.currentTimeMillis - startTime
      val msg = s"method=${request.method} uri=${request.uri} remote-address=${request.ipAddr} status=${result.header.status} user-agent=${request.userAgent} takeTime=${takeTime} ms"

      if (takeTime >= 1000) accessLogger.warn(s"*** ${msg} ***")
      else accessLogger.info(msg)

      resultFuture
    } recover {
      case NonFatal(ex) => {
        val takeTime = System.currentTimeMillis - startTime
        val msg = s"method=${request.method} uri=${request.uri} remote-address=${request.ipAddr} status=500 user-agent=${request.userAgent} takeTime=${takeTime}"
        accessLogger.error(msg)
        throw ex
      }
    }
  }
}
続きを読む

fileを開いて指定行数分取得する

fileを開いて、指定行数の分だけ取得するというロジックを作成していたのですが、
そもそもinputが指定行数以上あるかどうかを知りたかったので、そこもうまく取得できるような実装にする必要がありました。

BufferedReaderで最後の値が、nullになるので、null判定を行うことで、実装。

lisp脳なのか、headとtailでばかり考えていたのですが、
initとlastを使えばうまく実装できたので、メモとして。

ちなみに、aの値は以下のようになるのですが、

val a = Stream(1,2,??)

aの値代入が終わったあとでも以下のようにreader.readLine()を呼ぶと、aの値が変わります。

val reader = new Buffered...
val a = Iterator...
println(reader.readLine())
print(a)

なぜかは完全には把握していないのですが、Iteratorが遅延して評価しており、aの値が確定する前にreader.readLine()を読んでしまうのだろうということが仮説です。

Scalaの値クラスのバグ?

値クラスを使っていて不可解な挙動があったので、まとめたのとその対処法をメモしておきます。

値クラスとは

値クラスとはIntやStringが継承しているAnyValを継承させたクラスです。
一つの値しか持ちませんが拡張メソッドを実装できるため、DDDなどを実現するためのドメインモデルの記述に役立つ記法です。
値クラスと汎用トレイト - Scala Documentation

問題

コンパイル時の型は統一されていますが、実行時の型が不定という問題。

gist.github.com

上のように、コンパイル時の内部で保持している型は共にAttributesクラス(値クラス)なのですが、
実際に実行してみると、

  1. json4sから流し込んだ方:String型で保持
  2. 値クラスをそのままセット:Attributesクラスで保持

ということで、非常に不便な状況です。

対処法

続きを読む

ServerlessConf Tokyoに参加してきました。

serverlessconfに参加してきました。

serverlessに関しての知見があまりなかったので、すごい有意義な勉強会となりました。

  • そもそもserverlessとは
  • serverlessによって実現できること
  • serverlessの思想
  • 現状

そもそもserverlessとは

パネルディスカッションでも盛り上がっていましたが、 Serverlessとは何を指すのか?

実際にCPUなどのリソース管理をしないServerlessと FaaS(Function as a Service)の機能をベースとして構成としてのServerless の2つが議論に上がっていました。

自分なりには、前者に関してはいわゆるマネージドサービスであると思っているので、 後者のものをServerlessの概念として考えています。

serverlessによって実現できること

Serverless自体が注目されてたのは、AWS lambdaがきっかけです。 AWS lambdaとは、サーバを管理するのではなく、コード(ファンクション)を管理するのみで、デプロイもコードです。 lambdaが呼び出されるたびに毎回起動してファンクションが実行されます。

そのlambdaの登場によってリソース管理が必要なくなります。 今まではサーバにデプロイしていたため、そのサーバの要件に対してリソースが少ない場合、作り直す必要がありました。 しかし、lambdaを利用する場合、リソースに関しては気にしなくてもよいのです。 そう、圧倒的に運用負荷が下がるのです。

serverlessの思想

www.slideshare.net

上記のスライドを是非見てもらいたいのですが、serverless の思想が示されています

  1. オンデマンドで計算リソースを利用するべき
  2. 一つの目的のためのステートレスなファンクションを書くべき
  3. プッシュ型でイベント駆動のパイプラインで設計すべし
  4. フロントエンドに機能を充実させる
  5. 3rdパーティサービスを積極的に取り入れる

ItoNaoyaさんも言っていましたが、マイクロサービス的観点だと、1サーバに載せる機能は境界づけられたコンテキスト内の内容でした。 しかし上記の思想を取り入れると、lambdaで担保するものは1機能になっていきます。

現状

現状のlambdaでは、以下のデメリットがあります。

  • 計算時間がコストになりうる上、5分のタイムアウト制約もありますので、重い処理は実行できません。
  • lambdaなどのFaaSでは、使える言語が特定されてしまいます。
  • Javaなどは起動時間が遅いため、それをwebサービスのレスポンスとして利用するとサービスとして提供できるレベルに達しません。

薄いサービスならば作成できると思いますが、全てをserverlessで置き換えることはまだまだ難しそうです。 そもそも、その要件が満たせる状況になっても置き換えるかというのは疑問です。 というのも、複雑なビジネスロジックであればあるほど、コードとして再利用がし辛くなり抽象化ができなくなってしまうからです。

では、対応例として考えられるものは

  • botなどの厳しいレイテンシを求められないもの
  • バッチの発火
  • 薄いサービス
    でしょうか。

まとめ

serverlessという単語自体が曖昧な単語となってしまって、実際バズワードにもなりそうですが、 今後一つの潮流として、素早いサービスを作る上で絶対に避けて通れない考え方だと思います。

サービスを作る際に、serverlessも一つの手法の対象として考えれるようにキャッチアップしていく必要がありそうです。