Stop unused Artery outbound streams, #23967

* fix memory leak in SystemMessageDelivery
* initial set of tests for idle outbound associations, credit to mboogerd
* close inbound compression when quarantined, #23967
  * make sure compressions for quarantined are removed in case they are lingering around
  * also means that advertise will not be done for quarantined
  * remove tombstone in InboundCompressions
* simplify async callbacks by using invokeWithFeedback
* compression for old incarnation, #24400
  * it was fixed by the other previous changes
  * also confirmed by running the SimpleClusterApp with TCP
    as described in the ticket
* test with tcp and tls-tcp transport
  * handle the stop signals differently for tcp transport because they
    are converted to StreamTcpException
* cancel timers on shutdown
* share the top-level FR for all Association instances
* use linked queue for control and large streams, less memory usage
* remove quarantined idle Association completely after a configured delay
  * note that shallow Association instances may still lingering in the
    heap because of cached references from RemoteActorRef, which may
    be cached by LruBoundedCache (used by resolve actor ref).
    Those are small, since the queues have been removed, and the cache
    is bounded.
This commit is contained in:
Patrik Nordwall 2017-11-20 15:15:17 +01:00
parent 39c97c3306
commit 5e80bd97f2
23 changed files with 909 additions and 320 deletions

View file

@ -7,6 +7,8 @@ import java.util.ArrayDeque
import scala.concurrent.Future
import scala.concurrent.Promise
import scala.util.Try
import akka.Done
import akka.stream.Attributes
import akka.stream.FlowShape
@ -61,7 +63,6 @@ private[remote] object InboundControlJunction {
private[remote] trait ControlMessageSubject {
def attach(observer: ControlMessageObserver): Future[Done]
def detach(observer: ControlMessageObserver): Unit
def stopped: Future[Done]
}
private[remote] trait ControlMessageObserver {
@ -71,6 +72,8 @@ private[remote] object InboundControlJunction {
* of the envelope is always a `ControlMessage`.
*/
def notify(inboundEnvelope: InboundEnvelope): Unit
def controlSubjectCompleted(signal: Try[Done]): Unit
}
// messages for the stream callback
@ -92,7 +95,6 @@ private[remote] class InboundControlJunction
override val shape: FlowShape[InboundEnvelope, InboundEnvelope] = FlowShape(in, out)
override def createLogicAndMaterializedValue(inheritedAttributes: Attributes) = {
val stoppedPromise = Promise[Done]()
val logic = new GraphStageLogic(shape) with InHandler with OutHandler with ControlMessageSubject {
private var observers: Vector[ControlMessageObserver] = Vector.empty
@ -105,7 +107,10 @@ private[remote] class InboundControlJunction
observers = observers.filterNot(_ == observer)
}
override def postStop(): Unit = stoppedPromise.success(Done)
override def postStop(): Unit = {
observers.foreach(_.controlSubjectCompleted(Try(Done)))
observers = Vector.empty
}
// InHandler
override def onPush(): Unit = {
@ -133,8 +138,6 @@ private[remote] class InboundControlJunction
override def detach(observer: ControlMessageObserver): Unit =
callback.invoke(Dettach(observer))
override def stopped: Future[Done] =
stoppedPromise.future
}
(logic, logic)