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には数字が入る)が実行されなくなる
- 正確にいうとPlay Frameworkでローカルで開発用にDEVモードで実行した時に
原因詳細
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(
抜粋して変更点をかくと
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が出がちなのですが、きちんと確認した方がハマりどころをへらせそうですね。
さらに詳細
ああ、確かにそこハマりそうですね。2.7からEvolutionsが使ってるWebCommandのコードがアプリケーションの方に移動して内部的に色々変わりました。 https://t.co/xwKjNklcmL flyway-playでの対応も結構めんどくさかったです。
— Toshiyuki Takahashi (@tototoshi) April 19, 2019