UdpConnectedIntegrationSpec dns fail fix (#28558)
* More generous timeout for dns resolution failure #28133 * Use async-dns as workaround for JDK/glibc/whatever resolution bug * Handle Async DNS lookup failure in UDP and TCP connections
This commit is contained in:
parent
5bb9a7145a
commit
1df2c2d53a
4 changed files with 41 additions and 13 deletions
|
|
@ -6,15 +6,24 @@ package akka.io
|
|||
|
||||
import java.net.InetSocketAddress
|
||||
|
||||
import akka.testkit.{ AkkaSpec, ImplicitSender, TestProbe }
|
||||
import akka.util.ByteString
|
||||
import akka.actor.ActorRef
|
||||
import akka.testkit.SocketUtil.temporaryServerAddresses
|
||||
import akka.testkit.WithLogCapturing
|
||||
import akka.testkit.AkkaSpec
|
||||
import akka.testkit.ImplicitSender
|
||||
import akka.testkit.TestProbe
|
||||
import akka.util.ByteString
|
||||
|
||||
import scala.concurrent.duration._
|
||||
|
||||
class UdpConnectedIntegrationSpec extends AkkaSpec("""
|
||||
akka.loglevel = DEBUG
|
||||
akka.actor.debug.lifecycle = on
|
||||
akka.actor.debug.autoreceive = on
|
||||
akka.io.udp-connected.trace-logging = on
|
||||
# issues with dns resolution of non existent host hanging with the
|
||||
# Java native host resolution
|
||||
akka.io.dns.resolver = async-dns
|
||||
akka.loggers = ["akka.testkit.SilenceAllTestEventListener"]
|
||||
""") with ImplicitSender with WithLogCapturing {
|
||||
|
||||
|
|
@ -45,7 +54,7 @@ class UdpConnectedIntegrationSpec extends AkkaSpec("""
|
|||
val handler = TestProbe()
|
||||
val command = UdpConnected.Connect(handler.ref, InetSocketAddress.createUnresolved(serverAddress, 1234), None)
|
||||
commander.send(IO(UdpConnected), command)
|
||||
commander.expectMsg(6.seconds, UdpConnected.CommandFailed(command))
|
||||
commander.expectMsg(10.seconds, UdpConnected.CommandFailed(command))
|
||||
}
|
||||
|
||||
"report error if can not resolve (cached)" in {
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ package akka.io
|
|||
import java.net.{ ConnectException, InetSocketAddress }
|
||||
import java.nio.channels.{ SelectionKey, SocketChannel }
|
||||
|
||||
import akka.actor.Status.Failure
|
||||
|
||||
import scala.util.control.{ NoStackTrace, NonFatal }
|
||||
import scala.concurrent.duration._
|
||||
import akka.actor.{ ActorRef, ReceiveTimeout }
|
||||
|
|
@ -83,6 +85,11 @@ private[io] class TcpOutgoingConnection(
|
|||
}
|
||||
case ReceiveTimeout =>
|
||||
connectionTimeout()
|
||||
case Failure(ex) =>
|
||||
// async-dns responds with a Failure on DNS server lookup failure
|
||||
reportConnectFailure {
|
||||
throw new RuntimeException(ex)
|
||||
}
|
||||
}
|
||||
|
||||
def register(address: InetSocketAddress, registration: ChannelRegistration): Unit = {
|
||||
|
|
|
|||
|
|
@ -9,6 +9,8 @@ import java.nio.ByteBuffer
|
|||
import java.nio.channels.DatagramChannel
|
||||
import java.nio.channels.SelectionKey._
|
||||
|
||||
import akka.actor.Status.Failure
|
||||
|
||||
import scala.annotation.tailrec
|
||||
import scala.util.control.NonFatal
|
||||
import akka.actor.{ Actor, ActorLogging, ActorRef }
|
||||
|
|
@ -50,7 +52,9 @@ private[io] class UdpConnection(
|
|||
context.become(resolving())
|
||||
}
|
||||
} else {
|
||||
doConnect(remoteAddress)
|
||||
reportConnectFailure {
|
||||
doConnect(remoteAddress)
|
||||
}
|
||||
}
|
||||
|
||||
def resolving(): Receive = {
|
||||
|
|
@ -58,18 +62,22 @@ private[io] class UdpConnection(
|
|||
reportConnectFailure {
|
||||
doConnect(new InetSocketAddress(r.address(), remoteAddress.getPort))
|
||||
}
|
||||
case Failure(ex) =>
|
||||
// async-dns responds with a Failure on DNS server lookup failure
|
||||
reportConnectFailure {
|
||||
throw new RuntimeException(ex)
|
||||
}
|
||||
}
|
||||
|
||||
def doConnect(@unused address: InetSocketAddress): Unit = {
|
||||
reportConnectFailure {
|
||||
channel = DatagramChannel.open
|
||||
channel.configureBlocking(false)
|
||||
val socket = channel.socket
|
||||
options.foreach(_.beforeDatagramBind(socket))
|
||||
localAddress.foreach(socket.bind)
|
||||
channel.connect(remoteAddress)
|
||||
channelRegistry.register(channel, OP_READ)
|
||||
}
|
||||
channel = DatagramChannel.open
|
||||
channel.configureBlocking(false)
|
||||
val socket = channel.socket
|
||||
options.foreach(_.beforeDatagramBind(socket))
|
||||
localAddress.foreach(socket.bind)
|
||||
channel.connect(remoteAddress)
|
||||
channelRegistry.register(channel, OP_READ)
|
||||
|
||||
log.debug("Successfully connected to [{}]", remoteAddress)
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -47,6 +47,10 @@ object DnsProtocol {
|
|||
*/
|
||||
def srvRequestType(): RequestType = Srv
|
||||
|
||||
/**
|
||||
* Sending this to the [[AsyncDnsManager]] will either lead to a [[Resolved]] or a [[akka.actor.Status.Failure]] response.
|
||||
* If request type are both, both resolutions must succeed or the response is a failure.
|
||||
*/
|
||||
final case class Resolve(name: String, requestType: RequestType) extends ConsistentHashable {
|
||||
override def consistentHashKey: Any = name
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue