Gatling で API リクエストして期待するレスポンスが返るまで待機とリトライを繰り返したい

備忘録。前回の続編。

kntmr.hatenablog.com

Gatling で、ある API にリクエストして、期待するレスポンスが返るまで待機とリトライを繰り返したい。

以下は API のレスポンスからステータスを取り出して status=0 が返るまで 10 秒待機とリトライを繰り返すサンプル。API リクエストとか session の使い方とかイマイチな部分はあるかもしれない...。あと、実際にはリトライの最大試行回数を制限した方がいい。

doWhile + Thread#sleep

最初、doWhileThread#sleep でやろうとしたけどうまくいかず。(スレッドが溜まりすぎるのがよくないかもしれない)

doWhile - Loop statements | Gatling scenario scripting reference

val scn = scenario("example")
  .exec(
    // 最初にステータスの初期化が必要なものとする
    http("initialize")
      .post("/initialize")
      .check(status.is(200))
      .check(bodyString.saveAs("response"))
  ).exec(
    // レスポンスから status を取り出して session に詰める
    session => {
      val response = session("responseBody").as[String]
      val status = parse(response)
      session
        .set("status", status)
    }
  ).doWhile(
    // session から status を取り出してチェックして期待する結果出ない場合は sleep する
    // 本当は API リクエスト前に sleep したいが do ブロックで sleep すると API リクエストと session 引き継ぎがうまくできないのでここで sleep させる
    session => {
      val status = session("status").as[Int]
      if (status != 0) {
        Thread.sleep(10000)
      }
      status != 0 // true を返してる間は繰り返す
    }
  )(
    exec(
      // ステータス再取得
      http("status")
        .get("/status")
        .check(status.is(200))
        .check(bodyString.saveAs("response"))
    ).exec(
      // レスポンスから status を取り出して session に詰める
      session => {
        val response = session("responseBody").as[String]
        val status = parse(response)
        session
          .set("status", status)
      }
    )
  ).exec(
    //
    // 後続の処理...
    //
  )

asLongAs

最終的には asLongAs でいい感じに動くようになった。

asLongAs - Loop statements | Gatling scenario scripting reference

val scn = scenario("example")
  .exec(
    // 最初にステータスの初期化が必要なものとする
    http("initialize")
      .post("/initialize")
      .check(status.is(200))
      .check(bodyString.saveAs("response"))
  ).exec(
    // レスポンスから status を取り出して session に詰める
    session => {
      val response = session("responseBody").as[String]
      val status = parse(response)
      session
        .set("status", status)
    }
  ).asLongAs(
    session => {
      val status = session("status").as[Int]
      status != 0
    }
  ) {
    // 10秒待機
    pause(10 seconds)
    .exec(
      // ステータス再取得
      http("status")
        .get("/status")
        .check(status.is(200))
        .check(bodyString.saveAs("response"))
    ).exec(
      // レスポンスから status を取り出して session に詰める
      session => {
        val response = session("responseBody").as[String]
        val status = parse(response)
        session
          .set("status", status)
      }
    )
  }
  .exec(
    //
    // 後続の処理...
    //
  )

現場からは以上です。