playframework / playframework/play-ws

StandaloneAhcWSClient does not retry on read timeout

Open
#200 6 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

status:backlog
Dominant language
Scala
Stars
224
Forks
92
Avg merge
1d 19h
Merged PRs (30d)
28

Description

Play WS Version (2.5.x / etc)

"com.typesafe.play" %% "play-ahc-ws-standalone" % "1.1.3"

API (Scala / Java / Neither / Both)

Scala

Operating System (Ubuntu 15.10 / MacOS 10.10 / Windows 10)

MacOS Sierra 10.12.6

JDK (Oracle 1.8.0_72, OpenJDK 1.8.x, Azul Zing)

java version "1.8.0_144"
Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

Expected Behavior

Please describe the expected behavior of the issue, starting from the first action.

  1. Expect the client to retry on read (idle) timeout
Actual Behavior
  1. Evidence indicates there is no retry, based on the timing numbers printed in the test case below
Reproducible Test Case

Sample code that demonstrates the issue

package example

import akka.actor.ActorSystem
import akka.stream.ActorMaterializer
import org.scalatest._
import play.api.libs.ws.ahc.{AhcWSClientConfigFactory, StandaloneAhcWSClient}

import scala.concurrent.ExecutionContext.Implicits._
import scala.concurrent.duration._
import scala.concurrent.{Await, Future}
import scala.util.{Failure, Success, Try}

class HelloSpec extends FlatSpec with Matchers {
  "play-ws" should "work" in {
    implicit val system = ActorSystem()
    implicit val materializer = ActorMaterializer()

    val defaultConfig = AhcWSClientConfigFactory.forConfig()
    val config = defaultConfig.copy(maxRequestRetry = 6, wsClientConfig = defaultConfig.wsClientConfig.copy(idleTimeout = 2.seconds))
    println(s"config = ${config}")
    val wsClient = StandaloneAhcWSClient(config)
    val start = System.currentTimeMillis()
    val f = call(wsClient)
      .andThen { case _ => wsClient.close() }
      .andThen { case _ => system.terminate() }
    Try {
      Await.result(f, 20.seconds)
    } match {
      case Success(_) => println("Success")
      case Failure(_) =>
        val duration = System.currentTimeMillis() - start
        println(s"Failed in ${duration} ms")
    }
  }

  def call(wsClient: StandaloneAhcWSClient): Future[Unit] = {
    wsClient.url("https://httpbin.org/delay/10").get().map { response =>
      println(s"Got a response ${response.statusText}")
    }
  }
}

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the StandaloneAhcWSClient and AhcWSClientConfigFactory usage in the HelloSpec reproduction, especially maxRequestRetry and idleTimeout. Trace how a read timeout from the delayed request is handled and verify that the configured retries occur before the client closes; the test should complete with retry timing consistent with the configured retry count.

Written by the indexing model from the issue text.

Assessment

Tech stack
scala
Domain
api
Issue type
Bug
Difficulty
3/5
Estimated time
1-2 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.