Keep on moving

あんまりまとまってないことを書きますよ

Play Framework 2.7.x + EvolutionsでEvolutionsが動かなくなった時のTips

Play Frameworkのバージョンを 2.6から2.7に上げていてEvolutionsが動かなくなるパターンがあるので共有です。 限定的な条件なんですが、私はとてもハマったので次にハマった人のために情報を残しておこうと思います。 :sob:

TL;DR

  • Play Framework 2.6以下 + HTTP Request Handlersを拡張している + Evolutionsを使っている場合にEvolutionsが実行されなくなる
  • DefaultHttpRequestHandlerの書き方が変更になり2.6までのコンストラクターがDeprecatedになったのが原因
  • 2.7で追加されたコンストラクタを追加するように変更する必要がある

起こったこと

  • Play Framework 2.6以下 + HTTP Request Handlersを拡張している + Evolutionsを使っている場合にEvolutionsが実行されなくなる
    • 正確にいうとPlay Frameworkでローカルで開発用にDEVモードで実行した時に play_evolutionsテーブルが作られるが、 d.sql(dには数字が入る)が実行されなくなる

原因詳細

Play2.6で DefaultHttpRequestHandler を拡張していて、2.7に上げてビルドするとこんなwarningが出る。

19:50:51 [warn] /app/modules/CustomRequestHandler.scala:14:11: constructor DefaultHttpRequestHandler in class DefaultHttpRequestHandler is deprecated (since 2.7.0): Use the main DefaultHttpRequestHandler constructor 19:50:51 [warn] ) extends DefaultHttpRequestHandler(

www.playframework.com

www.playframework.com

抜粋して変更点をかくと

2.6

class VirtualHostRequestHandler @Inject() (errorHandler: HttpErrorHandler,
    configuration: HttpConfiguration, filters: HttpFilters,
    fooRouter: foo.Routes, barRouter: bar.Routes
  ) extends DefaultHttpRequestHandler(
    fooRouter, errorHandler, configuration, filters
  ) {

2.7

class VirtualHostRequestHandler @Inject() (
    webCommands: WebCommands,                // 2.7から追加されたもの
    optionalDevContext: OptionalDevContext,  // 2.7から追加されたもの
    errorHandler: HttpErrorHandler,
    configuration: HttpConfiguration, filters: HttpFilters,
    fooRouter: foo.Routes, barRouter: bar.Routes
  ) extends DefaultHttpRequestHandler(
    webCommands, optionalDevContext, fooRouter, errorHandler, configuration, filters
  ) {

この時2.6のドキュメントで触れられている方のコンストラクタを使うとこんなコードになる

playframework/HttpRequestHandler.scala at master · playframework/playframework · GitHub

  def this(router: Router, errorHandler: HttpErrorHandler, configuration: HttpConfiguration, filters: HttpFilters) = {
    this(new DefaultWebCommands, None, router, errorHandler, configuration, filters.filters)
  }

そう、この場合optionalDevContext がNoneになってしまう。

playframework/HttpRequestHandler.scala at master · playframework/playframework · GitHub

    // If we've got a BuildLink (i.e. if we're running in dev mode) then run the WebCommands.
    // The WebCommands will have a chance to intercept the request and override the result.
    // This is used by, for example, the evolutions code to present an evolutions UI to the
    // user when the access the web page through a browser.
    //
    // In prod mode this code will not be run.
    val webCommandResult: Option[Result] = optDevContext.flatMap { devContext: DevContext =>
      webCommands.handleWebCommand(request, devContext.buildLink, devContext.buildLink.projectPath)
    }

そう、この場合webCommandResultがNoneになってしまうのが原因でEvolutionsが起動しなくなっていました。 Evolutionsは Play FrameworkのWebCommandを使って実行されているため、影響を受けてしまったようです。 というわけで ここはdeprecatedなwarningが出ないように変更してやれば無事Evolutionsが実行されるようになります。

class VirtualHostRequestHandler @Inject() (
    webCommands: WebCommands,                // 2.7から追加されたもの
    optionalDevContext: OptionalDevContext,  // 2.7から追加されたもの
    errorHandler: HttpErrorHandler,
    configuration: HttpConfiguration, filters: HttpFilters,
    fooRouter: foo.Routes, barRouter: bar.Routes
  ) extends DefaultHttpRequestHandler(
    webCommands, optionalDevContext, fooRouter, errorHandler, configuration, filters
  ) {

気づいてしまえばすぐに直せるんですが、ちょっとわかりづらいですね。。Play Frameworkのバージョンを上げるとdeprecatedなwarningが出がちなのですが、きちんと確認した方がハマりどころをへらせそうですね。

さらに詳細

サンプル

github.com