!str #15121 MaterializerSettings now uses a config object
Resolves #15121
This commit is contained in:
parent
a25d0fcde9
commit
cc4fd5ca2c
76 changed files with 597 additions and 476 deletions
|
|
@ -3,20 +3,34 @@
|
|||
*/
|
||||
package akka.stream
|
||||
|
||||
import scala.concurrent.duration.FiniteDuration
|
||||
import akka.actor.ActorRefFactory
|
||||
import akka.stream.impl.ActorBasedFlowMaterializer
|
||||
import akka.stream.impl.Ast
|
||||
import akka.actor._
|
||||
import akka.stream.impl.{ ActorBasedFlowMaterializer, Ast, FlowNameCounter, StreamSupervisor }
|
||||
import com.typesafe.config.Config
|
||||
import org.reactivestreams.{ Publisher, Subscriber }
|
||||
import scala.concurrent.duration._
|
||||
import akka.actor.Deploy
|
||||
import akka.actor.ExtendedActorSystem
|
||||
import akka.actor.ActorContext
|
||||
import akka.stream.impl.StreamSupervisor
|
||||
import akka.stream.impl.FlowNameCounter
|
||||
|
||||
object FlowMaterializer {
|
||||
|
||||
/**
|
||||
* Scala API: Creates a FlowMaterializer which will execute every step of a transformation
|
||||
* pipeline within its own [[akka.actor.Actor]]. The required [[akka.actor.ActorRefFactory]]
|
||||
* (which can be either an [[akka.actor.ActorSystem]] or an [[akka.actor.ActorContext]])
|
||||
* will be used to create these actors, therefore it is *forbidden* to pass this object
|
||||
* to another actor if the factory is an ActorContext.
|
||||
*
|
||||
* The materializer's [[akka.stream.MaterializerSettings]] will be obtained from the
|
||||
* configuration of the `context`'s underlying [[akka.actor.ActorSystem]].
|
||||
*
|
||||
* The `namePrefix` is used as the first part of the names of the actors running
|
||||
* the processing steps. The default `namePrefix` is `"flow"`. The actor names are built up of
|
||||
* `namePrefix-flowNumber-flowStepNumber-stepName`.
|
||||
*/
|
||||
def apply(materializerSettings: Option[MaterializerSettings] = None, namePrefix: Option[String] = None)(implicit context: ActorRefFactory): FlowMaterializer = {
|
||||
val system = actorSystemOf(context)
|
||||
|
||||
val settings = materializerSettings getOrElse MaterializerSettings(system)
|
||||
apply(settings, namePrefix.getOrElse("flow"))(context)
|
||||
}
|
||||
|
||||
/**
|
||||
* Scala API: Creates a FlowMaterializer which will execute every step of a transformation
|
||||
* pipeline within its own [[akka.actor.Actor]]. The required [[akka.actor.ActorRefFactory]]
|
||||
|
|
@ -28,22 +42,43 @@ object FlowMaterializer {
|
|||
* the processing steps. The default `namePrefix` is `"flow"`. The actor names are built up of
|
||||
* `namePrefix-flowNumber-flowStepNumber-stepName`.
|
||||
*/
|
||||
def apply(settings: MaterializerSettings, namePrefix: Option[String] = None)(implicit context: ActorRefFactory): FlowMaterializer = {
|
||||
val system = context match {
|
||||
case s: ExtendedActorSystem ⇒ s
|
||||
case c: ActorContext ⇒ c.system
|
||||
case null ⇒ throw new IllegalArgumentException("ActorRefFactory context must be defined")
|
||||
case _ ⇒ throw new IllegalArgumentException(s"ActorRefFactory context must be a ActorSystem or ActorContext, " +
|
||||
"got [${_contex.getClass.getName}]")
|
||||
}
|
||||
def apply(materializerSettings: MaterializerSettings, namePrefix: String)(implicit context: ActorRefFactory): FlowMaterializer = {
|
||||
val system = actorSystemOf(context)
|
||||
|
||||
new ActorBasedFlowMaterializer(
|
||||
settings,
|
||||
context.actorOf(StreamSupervisor.props(settings).withDispatcher(settings.dispatcher)),
|
||||
materializerSettings,
|
||||
context.actorOf(StreamSupervisor.props(materializerSettings).withDispatcher(materializerSettings.dispatcher)),
|
||||
FlowNameCounter(system).counter,
|
||||
namePrefix.getOrElse("flow"))
|
||||
namePrefix)
|
||||
}
|
||||
|
||||
/**
|
||||
* Scala API: Creates a FlowMaterializer which will execute every step of a transformation
|
||||
* pipeline within its own [[akka.actor.Actor]]. The required [[akka.actor.ActorRefFactory]]
|
||||
* (which can be either an [[akka.actor.ActorSystem]] or an [[akka.actor.ActorContext]])
|
||||
* will be used to create these actors, therefore it is *forbidden* to pass this object
|
||||
* to another actor if the factory is an ActorContext.
|
||||
*
|
||||
* The `namePrefix` is used as the first part of the names of the actors running
|
||||
* the processing steps. The default `namePrefix` is `"flow"`. The actor names are built up of
|
||||
* `namePrefix-flowNumber-flowStepNumber-stepName`.
|
||||
*/
|
||||
def apply(materializerSettings: MaterializerSettings)(implicit context: ActorRefFactory): FlowMaterializer =
|
||||
apply(Some(materializerSettings), None)
|
||||
|
||||
/**
|
||||
* Java API: Creates a FlowMaterializer which will execute every step of a transformation
|
||||
* pipeline within its own [[akka.actor.Actor]]. The required [[akka.actor.ActorRefFactory]]
|
||||
* (which can be either an [[akka.actor.ActorSystem]] or an [[akka.actor.ActorContext]])
|
||||
* will be used to create these actors, therefore it is *forbidden* to pass this object
|
||||
* to another actor if the factory is an ActorContext.
|
||||
*
|
||||
* Defaults the actor name prefix used to name actors running the processing steps to `"flow"`.
|
||||
* The actor names are built up of `namePrefix-flowNumber-flowStepNumber-stepName`.
|
||||
*/
|
||||
def create(context: ActorRefFactory): FlowMaterializer =
|
||||
apply()(context)
|
||||
|
||||
/**
|
||||
* Java API: Creates a FlowMaterializer which will execute every step of a transformation
|
||||
* pipeline within its own [[akka.actor.Actor]]. The required [[akka.actor.ActorRefFactory]]
|
||||
|
|
@ -52,7 +87,33 @@ object FlowMaterializer {
|
|||
* to another actor if the factory is an ActorContext.
|
||||
*/
|
||||
def create(settings: MaterializerSettings, context: ActorRefFactory): FlowMaterializer =
|
||||
apply(settings)(context)
|
||||
apply(Option(settings), None)(context)
|
||||
|
||||
/**
|
||||
* Java API: Creates a FlowMaterializer which will execute every step of a transformation
|
||||
* pipeline within its own [[akka.actor.Actor]]. The required [[akka.actor.ActorRefFactory]]
|
||||
* (which can be either an [[akka.actor.ActorSystem]] or an [[akka.actor.ActorContext]])
|
||||
* will be used to create these actors, therefore it is *forbidden* to pass this object
|
||||
* to another actor if the factory is an ActorContext.
|
||||
*
|
||||
* The `namePrefix` is used as the first part of the names of the actors running
|
||||
* the processing steps. The default `namePrefix` is `"flow"`. The actor names are built up of
|
||||
* `namePrefix-flowNumber-flowStepNumber-stepName`.
|
||||
*/
|
||||
def create(settings: MaterializerSettings, context: ActorRefFactory, namePrefix: String): FlowMaterializer =
|
||||
apply(Option(settings), Option(namePrefix))(context)
|
||||
|
||||
private def actorSystemOf(context: ActorRefFactory): ActorSystem = {
|
||||
val system = context match {
|
||||
case s: ExtendedActorSystem ⇒ s
|
||||
case c: ActorContext ⇒ c.system
|
||||
case null ⇒ throw new IllegalArgumentException("ActorRefFactory context must be defined")
|
||||
case _ ⇒
|
||||
throw new IllegalArgumentException(s"ActorRefFactory context must be a ActorSystem or ActorContext, got [${context.getClass.getName}]")
|
||||
}
|
||||
system
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -89,13 +150,46 @@ abstract class FlowMaterializer(val settings: MaterializerSettings) {
|
|||
}
|
||||
|
||||
object MaterializerSettings {
|
||||
private val defaultSettings = new MaterializerSettings
|
||||
/**
|
||||
* Java API: Default settings.
|
||||
* Refine the settings using [[MaterializerSettings#withBuffer]],
|
||||
* Create [[MaterializerSettings]].
|
||||
*
|
||||
* You can refine the configuration based settings using [[MaterializerSettings#withBuffer]],
|
||||
* [[MaterializerSettings#withFanOut]], [[MaterializerSettings#withSubscriptionTimeout]]
|
||||
*/
|
||||
def create(): MaterializerSettings = defaultSettings
|
||||
def apply(system: ActorSystem): MaterializerSettings =
|
||||
apply(system.settings.config.getConfig("akka.stream.materializer"))
|
||||
|
||||
/**
|
||||
* Create [[MaterializerSettings]].
|
||||
*
|
||||
* You can refine the configuration based settings using [[MaterializerSettings#withBuffer]],
|
||||
* [[MaterializerSettings#withFanOut]], [[MaterializerSettings#withSubscriptionTimeout]]
|
||||
*/
|
||||
def apply(config: Config): MaterializerSettings =
|
||||
MaterializerSettings(
|
||||
config.getInt("initial-input-buffer-size"),
|
||||
config.getInt("max-input-buffer-size"),
|
||||
config.getInt("initial-fan-out-buffer-size"),
|
||||
config.getInt("max-fan-out-buffer-size"),
|
||||
config.getString("dispatcher"))
|
||||
|
||||
/**
|
||||
* Java API
|
||||
*
|
||||
* You can refine the configuration based settings using [[MaterializerSettings#withBuffer]],
|
||||
* [[MaterializerSettings#withFanOut]], [[MaterializerSettings#withSubscriptionTimeout]]
|
||||
*/
|
||||
def create(system: ActorSystem): MaterializerSettings =
|
||||
apply(system)
|
||||
|
||||
/**
|
||||
* Java API
|
||||
*
|
||||
* You can refine the configuration based settings using [[MaterializerSettings#withBuffer]],
|
||||
* [[MaterializerSettings#withFanOut]], [[MaterializerSettings#withSubscriptionTimeout]]
|
||||
*/
|
||||
def create(config: Config): MaterializerSettings =
|
||||
apply(config)
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -104,33 +198,33 @@ object MaterializerSettings {
|
|||
*
|
||||
* This will likely be replaced in the future by auto-tuning these values at runtime.
|
||||
*/
|
||||
case class MaterializerSettings(
|
||||
initialFanOutBufferSize: Int = 4,
|
||||
maxFanOutBufferSize: Int = 16,
|
||||
initialInputBufferSize: Int = 4,
|
||||
maximumInputBufferSize: Int = 16,
|
||||
dispatcher: String = Deploy.NoDispatcherGiven) {
|
||||
|
||||
private def isPowerOfTwo(n: Integer): Boolean = (n & (n - 1)) == 0
|
||||
require(initialFanOutBufferSize > 0, "initialFanOutBufferSize must be > 0")
|
||||
require(maxFanOutBufferSize > 0, "maxFanOutBufferSize must be > 0")
|
||||
require(initialFanOutBufferSize <= maxFanOutBufferSize,
|
||||
s"initialFanOutBufferSize($initialFanOutBufferSize) must be <= maxFanOutBufferSize($maxFanOutBufferSize)")
|
||||
final case class MaterializerSettings(
|
||||
initialInputBufferSize: Int,
|
||||
maxInputBufferSize: Int,
|
||||
initialFanOutBufferSize: Int,
|
||||
maxFanOutBufferSize: Int,
|
||||
dispatcher: String) {
|
||||
|
||||
require(initialInputBufferSize > 0, "initialInputBufferSize must be > 0")
|
||||
require(isPowerOfTwo(initialInputBufferSize), "initialInputBufferSize must be a power of two")
|
||||
require(maximumInputBufferSize > 0, "maximumInputBufferSize must be > 0")
|
||||
require(isPowerOfTwo(maximumInputBufferSize), "initialInputBufferSize must be a power of two")
|
||||
require(initialInputBufferSize <= maximumInputBufferSize,
|
||||
s"initialInputBufferSize($initialInputBufferSize) must be <= maximumInputBufferSize($maximumInputBufferSize)")
|
||||
|
||||
def withBuffer(initialInputBufferSize: Int, maximumInputBufferSize: Int): MaterializerSettings =
|
||||
copy(initialInputBufferSize = initialInputBufferSize, maximumInputBufferSize = maximumInputBufferSize)
|
||||
require(maxInputBufferSize > 0, "maxInputBufferSize must be > 0")
|
||||
require(isPowerOfTwo(maxInputBufferSize), "maxInputBufferSize must be a power of two")
|
||||
require(initialInputBufferSize <= maxInputBufferSize, s"initialInputBufferSize($initialInputBufferSize) must be <= maxInputBufferSize($maxInputBufferSize)")
|
||||
|
||||
def withFanOut(initialFanOutBufferSize: Int, maxFanOutBufferSize: Int): MaterializerSettings =
|
||||
copy(initialFanOutBufferSize = initialFanOutBufferSize, maxFanOutBufferSize = maxFanOutBufferSize)
|
||||
require(initialFanOutBufferSize > 0, "initialFanOutBufferSize must be > 0")
|
||||
|
||||
def withDispatcher(dispatcher: String): MaterializerSettings = copy(dispatcher = dispatcher)
|
||||
require(maxFanOutBufferSize > 0, "maxFanOutBufferSize must be > 0")
|
||||
require(isPowerOfTwo(maxFanOutBufferSize), "maxFanOutBufferSize must be a power of two")
|
||||
require(initialFanOutBufferSize <= maxFanOutBufferSize, s"initialFanOutBufferSize($initialFanOutBufferSize) must be <= maxFanOutBufferSize($maxFanOutBufferSize)")
|
||||
|
||||
def withInputBuffer(initialSize: Int, maxSize: Int): MaterializerSettings =
|
||||
copy(initialInputBufferSize = initialSize, maxInputBufferSize = maxSize)
|
||||
|
||||
def withFanOutBuffer(initialSize: Int, maxSize: Int): MaterializerSettings =
|
||||
copy(initialFanOutBufferSize = initialSize, maxFanOutBufferSize = maxSize)
|
||||
|
||||
def withDispatcher(dispatcher: String): MaterializerSettings =
|
||||
copy(dispatcher = dispatcher)
|
||||
|
||||
private def isPowerOfTwo(n: Integer): Boolean = (n & (n - 1)) == 0
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue