テストステ論

高テス協会会長が, テストステロンに関する情報をお届けします.

(akashic report) 約束、ペイロードを消化すること

ホスト(Mac)上でakashic-storageを立ち上げて, Vagrantで作ったVM上からデフォルトゲートウェイ経由でホストにs3-testsを投げる. ホストではIntelliJを使ってデバグが出来るという仕組みを導入した. これでs3-testsでfailするものを一つずつ確実に駆逐していくことが出来る.

VMからs3-testsを投げてみると, POSTリクエストを投げるリクエストでハングしてしまう. タイムアウトも効かない. 試しにPOSTが来た時に, テストが期待してる204をいきなり返すことにすると以下のようなエラーメッセージが現れた.

[WARN] [02/08/2016 15:59:28.446] [akashic-storage-akka.actor.default-dispatcher-4] [ActorSystem(akashic-storage)] Sending 2xx response before end of request was received... Note that the connection will be closed after this response. Also, many clients will not read early responses! Consider waiting for the request end before dispatching this response!

これは, リクエストのペイロードを全部消化せずに204を返しているのがおかしいと言っている. "many clients will not read early responses"がハングする理由だろうか. レスポンスは返しているけど, クライアントがシカトするので, 何かタイムアウトの手の届かぬパスに行ってるというのが私の推測である.

そもそも, 現在のakashic-storageはPOSTを実装していない. これは, finchでPOSTを実装するのが難しかったからやらなかったというだけで, akka-httpならば出来る. さきほどの推測が正しければ, その実装していないPOSTが投げられたことによって, 単に400か500が返ってしまい, early responseになっていたというのが真実ということになる.

当面, POSTは後回しにされるし, 最終的にも実装しないAPIはある. そのようなAPIが来て仮にペイロードを持っていた場合に, この問題が起こらぬように, routingの最後に「entityを全消化してcompleteする」というrouteを追加した.

  val ignoreEntity: Directive0 = entity(as[ByteString]).tflatMap(_ => pass)
  val unmatchRoute =
    // We need to extract entity to consume the payload
    // otherwise client never knows the end of connection.
    ignoreEntity { complete(StatusCodes.BadRequest, HttpEntity.Empty) }

  val route =
    apiRoute ~
    unmatchRoute

このignoreEntityは, 公式のDirectivesにあっても良かったと思うがなかったので自作した. だめもとでPRしてみようと思う. すでにもっと良い方法があるならば教えて欲しい.