From 96eed177dca3cf890912d35338e6c2c0005942e8 Mon Sep 17 00:00:00 2001 From: Christopher Batey Date: Wed, 29 May 2019 09:50:28 +0100 Subject: [PATCH] Make netty and aeron dependencies optional (#27017) * Make netty and aeron dependencies optional * Include agrona as a mandatory dependency (used in compression tables) Refs #25169 --- .../project/migration-guide-2.5.x-2.6.x.md | 17 +++++--- akka-docs/src/main/paradox/remoting-artery.md | 12 ++++++ akka-docs/src/main/paradox/remoting.md | 9 ++++ .../akka/remote/RemoteActorRefProvider.scala | 41 +++++++++++++++++++ build.sbt | 5 ++- project/Dependencies.scala | 17 ++++++-- 6 files changed, 92 insertions(+), 9 deletions(-) diff --git a/akka-docs/src/main/paradox/project/migration-guide-2.5.x-2.6.x.md b/akka-docs/src/main/paradox/project/migration-guide-2.5.x-2.6.x.md index f6d330816e..04fc42e81a 100644 --- a/akka-docs/src/main/paradox/project/migration-guide-2.5.x-2.6.x.md +++ b/akka-docs/src/main/paradox/project/migration-guide-2.5.x-2.6.x.md @@ -123,7 +123,9 @@ blocking and protect a bit against starving the internal actors. Since the inter the default dispatcher has been adjusted down to `1.0` which means the number of threads will be one per core, but at least `8` and at most `64`. This can be tuned using the individual settings in `akka.actor.default-dispatcher.fork-join-executor`. -## Default remoting is now Artery TCP +@@ Remoting + +### Default remoting is now Artery TCP @ref[Artery TCP](../remoting-artery.md) is now the default remoting implementation. Classic remoting has been deprecated and will be removed in `2.7.0`. @@ -134,7 +136,7 @@ Previously, Akka contained a shaded copy of the ForkJoinPool. In benchmarks, we keeping our own copy, so from Akka 2.6 on, the default FJP from the JDK will be used. The Akka FJP copy was removed. -### Migrating from classic remoting to Artery +#### Migrating from classic remoting to Artery Artery has the same functionality as classic remoting and you should normally only have to change the configuration to switch. @@ -164,7 +166,7 @@ If using SSL then `tcp-tls` needs to be enabled and setup. See @ref[Artery docs for how to do this. -### Migration from 2.5.x Artery to 2.6.x Artery +#### Migration from 2.5.x Artery to 2.6.x Artery The following defaults have changed: @@ -189,18 +191,23 @@ For TCP: * `akka.remote.artery.advanced.connection-timeout` to `akka.remote.artery.advanced.tcp.connection-timeout` -### Remaining with Classic remoting (not recommended) +#### Remaining with Classic remoting (not recommended) Classic remoting is deprecated but can be used in `2.6.` Any configuration under `akka.remote` that is specific to classic remoting needs to be moved to `akka.remote.classic`. To see which configuration options are specific to classic search for them in: [`akka-remote/reference.conf`](/akka-remote/src/main/resources/reference.conf) -## Netty UDP has been removed +### Netty UDP has been removed Classic remoting over UDP has been deprecated since `2.5.0` and now has been removed. To continue to use UDP configure @ref[Artery UDP](../remoting-artery.md#configuring-ssl-tls-for-akka-remoting) or migrate to Artery TCP. A full cluster restart is required to change to Artery. +### Remoting dependencies have been made optional + +Classic remoting depends on Netty and Artery UDP depends on Aeron. These are now both optional dependencies that need +to be explicitly added. See @ref[classic remoting](../remoting.md) or [artery remoting](../remoting-artery.md) for instructions. + ## Streams ### StreamRefs diff --git a/akka-docs/src/main/paradox/remoting-artery.md b/akka-docs/src/main/paradox/remoting-artery.md index b29795cbe2..b163d57e37 100644 --- a/akka-docs/src/main/paradox/remoting-artery.md +++ b/akka-docs/src/main/paradox/remoting-artery.md @@ -23,6 +23,18 @@ To use Artery Remoting, you must add the following dependency in your project: version=$akka.version$ } +Artery UDP depends on Aeron. This needs to be explicitly added as a dependency if using `aeron-udp` so that users +not using Artery remoting do not have Aeron on the classpath: + +@@dependency[sbt,Maven,Gradle] { + group=io.aeron + artifact=aeron-driver + version="$aeron_version$" + group2=io.aeron + artifact2=aeron-client + version2="$aeron_version$" +} + If migrating from classic remoting see @ref:[what's new in Artery](#what-is-new-in-artery) ## Configuration diff --git a/akka-docs/src/main/paradox/remoting.md b/akka-docs/src/main/paradox/remoting.md index 507bfc71f3..da9c260ce3 100644 --- a/akka-docs/src/main/paradox/remoting.md +++ b/akka-docs/src/main/paradox/remoting.md @@ -30,6 +30,15 @@ To use Akka Remoting, you must add the following dependency in your project: version=$akka.version$ } +Classic remoting depends on Netty. This needs to be explicitly added as a dependency so that users +not using classic remoting do not have to have Netty on the classpath: + +@@dependency[sbt,Maven,Gradle] { + group=io.netty + artifact=netty + version=$netty_version$ +} + ## Configuration To enable classic remoting in your Akka project you should, at a minimum, add the following changes diff --git a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala index 5f3dd97bb9..2b6e7c45cd 100644 --- a/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala +++ b/akka-remote/src/main/scala/akka/remote/RemoteActorRefProvider.scala @@ -12,6 +12,7 @@ import akka.event.Logging.Error import akka.pattern.pipe import scala.util.control.NonFatal +import scala.util.Failure import akka.actor.SystemGuardian.{ RegisterTerminationHook, TerminationHook, TerminationHookDone } import scala.util.control.Exception.Catcher @@ -22,6 +23,7 @@ import akka.dispatch.{ RequiresMessageQueue, UnboundedMessageQueueSemantics } import akka.remote.artery.ArteryTransport import akka.remote.artery.aeron.ArteryAeronUdpTransport import akka.remote.artery.ArterySettings +import akka.remote.artery.ArterySettings.AeronUpd import akka.util.{ ErrorMessages, OptionVal } import akka.remote.artery.OutboundEnvelope import akka.remote.artery.SystemMessageDelivery.SystemMessageEnvelope @@ -35,6 +37,7 @@ import com.github.ghik.silencer.silent */ @InternalApi private[akka] object RemoteActorRefProvider { + private final case class Internals(transport: RemoteTransport, remoteDaemon: InternalActorRef) extends NoSerializationVerificationNeeded @@ -207,6 +210,12 @@ private[akka] class RemoteActorRefProvider( remoteSettings.configureDispatcher(Props(classOf[RemotingTerminator], local.systemGuardian)), "remoting-terminator") + if (remoteSettings.Artery.Enabled && remoteSettings.Artery.Transport == AeronUpd) { + checkAeronOnClassPath(system) + } else if (!remoteSettings.Artery.Enabled) { + checkNettyOnClassPath(system) + } // artery tcp has no dependencies + val internals = Internals( remoteDaemon = { val d = new RemoteSystemDaemon( @@ -239,6 +248,38 @@ private[akka] class RemoteActorRefProvider( remoteDeploymentWatcher = createRemoteDeploymentWatcher(system) } + private def checkNettyOnClassPath(system: ActorSystemImpl): Unit = { + // TODO change link to current once 2.6 is out + checkClassOrThrow( + system, + "org.jboss.netty.channel.Channel", + "Classic", + "Netty", + "https://doc.akka.io/docs/akka/2.6/remoting.html") + } + + private def checkAeronOnClassPath(system: ActorSystemImpl): Unit = { + // TODO change link to current once 2.6 is out + val arteryLink = "https://doc.akka.io/docs/akka/2.6/remoting-artery.html" + // using classes that are used so will fail to compile if they get removed from Aeron + checkClassOrThrow(system, "io.aeron.driver.MediaDriver", "Artery", "Aeron driver", arteryLink) + checkClassOrThrow(system, "io.aeron.Aeron", "Artery", "Aeron client", arteryLink) + } + + private def checkClassOrThrow( + system: ActorSystemImpl, + className: String, + remoting: String, + libraryMissing: String, + link: String): Unit = { + system.dynamicAccess.getClassFor(className) match { + case Failure(_: ClassNotFoundException | _: NoClassDefFoundError) => + throw new IllegalStateException( + s"$remoting remoting is enabled but $libraryMissing is not on the classpath, it must be added explicitly. See $link") + case _ => + } + } + protected def createRemoteWatcher(system: ActorSystemImpl): ActorRef = { import remoteSettings._ val failureDetector = createRemoteWatcherFailureDetector(system) diff --git a/build.sbt b/build.sbt index 6f04ae9d0c..dd146a87f5 100644 --- a/build.sbt +++ b/build.sbt @@ -222,7 +222,9 @@ lazy val docs = akkaModule("akka-docs") "google.analytics.domain.name" -> "akka.io", "signature.akka.base_dir" -> (baseDirectory in ThisBuild).value.getAbsolutePath, "fiddle.code.base_dir" -> (sourceDirectory in Test).value.getAbsolutePath, - "fiddle.akka.base_dir" -> (baseDirectory in ThisBuild).value.getAbsolutePath), + "fiddle.akka.base_dir" -> (baseDirectory in ThisBuild).value.getAbsolutePath, + "aeron_version" -> Dependencies.aeronVersion, + "netty_version" -> Dependencies.nettyVersion), Compile / paradoxGroups := Map("Language" -> Seq("Scala", "Java")), resolvers += Resolver.jcenterRepo, apidocRootPackage := "akka", @@ -251,6 +253,7 @@ lazy val jackson = akkaModule("akka-serialization-jackson") lazy val multiNodeTestkit = akkaModule("akka-multi-node-testkit") .dependsOn(remote, testkit) + .settings(Dependencies.multiNodeTestkit) .settings(Protobuf.settings) .settings(AutomaticModuleName.settings("akka.remote.testkit")) .settings(AkkaBuild.mayChangeSettings) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index ee16f48300..dd30a9154c 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -17,7 +17,11 @@ object Dependencies { val junitVersion = "4.12" val slf4jVersion = "1.7.25" val scalaXmlVersion = "1.0.6" + // check agrona version when updating this val aeronVersion = "1.15.1" + // needs to be inline with the aeron version + val agronaVersion = "0.9.31" + val nettyVersion = "3.10.6.Final" val jacksonVersion = "2.9.9" val scala212Version = "2.12.8" @@ -52,7 +56,7 @@ object Dependencies { // Compile val config = "com.typesafe" % "config" % "1.3.4" // ApacheV2 - val netty = "io.netty" % "netty" % "3.10.6.Final" // ApacheV2 + val netty = "io.netty" % "netty" % nettyVersion // ApacheV2 val scalaXml = "org.scala-lang.modules" %% "scala-xml" % scalaXmlVersion // Scala License val scalaReflect = ScalaVersionDependentModuleID.versioned("org.scala-lang" % "scala-reflect" % _) // Scala License @@ -82,6 +86,8 @@ object Dependencies { val aeronDriver = "io.aeron" % "aeron-driver" % aeronVersion // ApacheV2 val aeronClient = "io.aeron" % "aeron-client" % aeronVersion // ApacheV2 + // Added explicitly for when artery tcp is used + val agrona = "org.agrona" % "agrona" % agronaVersion // ApacheV2 val jacksonCore = "com.fasterxml.jackson.core" % "jackson-core" % jacksonVersion // ApacheV2 val jacksonAnnotations = "com.fasterxml.jackson.core" % "jackson-annotations" % jacksonVersion // ApacheV2 @@ -180,9 +186,14 @@ object Dependencies { val actorTestkitTyped = l ++= Seq(Provided.junit, Provided.scalatest.value) - val remote = l ++= Seq(netty, aeronDriver, aeronClient, Test.junit, Test.scalatest.value, Test.jimfs) + val remoteDependencies = Seq(netty, aeronDriver, aeronClient) + val remoteOptionalDependencies = remoteDependencies.map(_ % "optional") - val remoteTests = l ++= Seq(Test.junit, Test.scalatest.value, Test.scalaXml) + val remote = l ++= Seq(agrona, Test.junit, Test.scalatest.value, Test.jimfs) ++ remoteOptionalDependencies + + val remoteTests = l ++= Seq(Test.junit, Test.scalatest.value, Test.scalaXml) ++ remoteDependencies + + val multiNodeTestkit = l ++= remoteOptionalDependencies val cluster = l ++= Seq(Test.junit, Test.scalatest.value)