diff --git a/build.sbt b/build.sbt index d97fc8fca..79b1e87d3 100644 --- a/build.sbt +++ b/build.sbt @@ -16,6 +16,7 @@ inThisBuild( organizationHomepage := Some(url("https://lightbend.com")), startYear := Some(2019), licenses += ("Apache-2.0", new URL("https://www.apache.org/licenses/LICENSE-2.0.txt")), + resolvers += "Akka Snapshots" at "https://repo.akka.io/snapshots/", // FIXME for akka-protobuf-v390 homepage := Some(url("https://cloudstate.io")), scmInfo := Some( ScmInfo( @@ -49,23 +50,38 @@ name := "cloudstate" val GrpcJavaVersion = "1.22.1" val GraalAkkaVersion = "0.5.0" -val AkkaVersion = "2.6.4" +val AkkaVersion = "2.6.5" val AkkaHttpVersion = "10.1.11" val AkkaManagementVersion = "1.0.5" val AkkaPersistenceCassandraVersion = "0.102" val PrometheusClientVersion = "0.6.0" val ScalaTestVersion = "3.0.5" -val ProtobufVersion = "3.10.0" +val ProtobufVersion = "3.9.0" // We use this version because it is the latest which works with native-image 20.0.0 val GraalVersion = "20.0.0" val DockerBaseImageVersion = "adoptopenjdk/openjdk11:debian" val DockerBaseImageJavaLibraryPath = "${JAVA_HOME}/lib" -def excludeTheseDependencies = Seq( +val excludeTheseDependencies: Seq[ExclusionRule] = Seq( ExclusionRule("io.netty", "netty"), // grpc-java is using grpc-netty-shaded ExclusionRule("io.aeron"), // we're using Artery-TCP ExclusionRule("org.agrona") // and we don't need this either ) +def akkaDependency(name: String, excludeThese: ExclusionRule*) = + "com.typesafe.akka" %% name % AkkaVersion excludeAll ((excludeTheseDependencies ++ excludeThese): _*) + +def akkaHttpDependency(name: String, excludeThese: ExclusionRule*) = + "com.typesafe.akka" %% name % AkkaHttpVersion excludeAll ((excludeTheseDependencies ++ excludeThese): _*) + +def akkaManagementDependency(name: String, excludeThese: ExclusionRule*) = + "com.lightbend.akka.management" %% name % AkkaManagementVersion excludeAll ((excludeTheseDependencies ++ excludeThese): _*) + +def akkaDiscoveryDependency(name: String, excludeThese: ExclusionRule*) = + "com.lightbend.akka.discovery" %% name % AkkaManagementVersion excludeAll ((excludeTheseDependencies ++ excludeThese): _*) + +def akkaPersistenceCassandraDependency(name: String, excludeThese: ExclusionRule*) = + "com.typesafe.akka" %% name % AkkaPersistenceCassandraVersion excludeAll ((excludeTheseDependencies ++ excludeThese): _*) + def common: Seq[Setting[_]] = Seq( headerMappings := headerMappings.value ++ Seq( de.heikoseeberger.sbtheader.FileType("proto") -> HeaderCommentStyle.cppStyleLineComment, @@ -73,6 +89,7 @@ def common: Seq[Setting[_]] = Seq( ), // Akka gRPC overrides the default ScalaPB setting including the file base name, let's override it right back. akkaGrpcCodeGeneratorSettings := Seq(), + excludeDependencies += "com.typesafe.akka" %% "akka-protobuf-v3", // akka-protobuf-v3 shades protobuf-java 3.10.0 which is not compatible with native-image 20.0.0 excludeFilter in headerResources := HiddenFileFilter || GlobFilter("reflection.proto"), javaOptions in Test ++= Seq("-Xms1G", "-XX:+CMSClassUnloadingEnabled", "-XX:+UseConcMarkSweepGC") ) @@ -306,6 +323,22 @@ def nativeImageDockerSettings: Seq[Setting[_]] = dockerSettings ++ Seq( } ) +def assemblySettings(jarName: String) = + Seq( + mainClass in assembly := (mainClass in Compile).value, + assemblyJarName in assembly := jarName, + test in assembly := {}, + // logLevel in assembly := Level.Debug, + assemblyMergeStrategy in assembly := { + /*ADD CUSTOMIZATIONS HERE*/ + case PathList("META-INF", "io.netty.versions.properties") => MergeStrategy.last + case PathList(ps @ _*) if ps.last endsWith ".proto" => MergeStrategy.last + case x => + val oldStrategy = (assemblyMergeStrategy in assembly).value + oldStrategy(x) + } + ) + def sharedNativeImageSettings(targetDir: File) = Seq( //"-O1", // Optimization level "-H:ResourceConfigurationFiles=" + targetDir / "resource-config.json", @@ -316,8 +349,8 @@ def sharedNativeImageSettings(targetDir: File) = Seq( "-H:+AllowVMInspection", "-H:-RuntimeAssertions", "-H:+ReportExceptionStackTraces", - // "-H:+PrintAnalysisCallTree" // Uncomment to dump the entire call graph, useful for debugging native-image failing builds - // "-H:ReportAnalysisForbiddenType=java.lang.invoke.MethodHandleImpl$AsVarargsCollector" // Uncomment and specify a type which will break analysis, useful to figure out reachability + // "-H:+PrintAnalysisCallTree", // Uncomment to dump the entire call graph, useful for debugging native-image failing builds + //"-H:ReportAnalysisForbiddenType=java.lang.invoke.MethodHandleImpl$AsVarargsCollector", // Uncomment and specify a type which will break analysis, useful to figure out reachability "-H:-PrintUniverse", // if "+" prints out all classes which are included "-H:-NativeArchitecture", // if "+" Compiles the native image to customize to the local CPU arch "-H:Class=" + "io.cloudstate.proxy.CloudStateProxyMain", @@ -336,14 +369,14 @@ def sharedNativeImageSettings(targetDir: File) = Seq( "akka.dispatch.affinity", "akka.util", "com.google.Protobuf", - "com.typesafe.config", - "scala.runtime.Statics$VM" ).mkString("=", ",", ""), - "-H:ClassInitialization=com.typesafe.config.impl.ConfigImpl$EnvVariablesHolder:rerun", - "-H:ClassInitialization=com.typesafe.config.impl.ConfigImpl$SystemPropertiesHolder:rerun", - "-H:ClassInitialization=com.typesafe.config.impl.ConfigImpl$LoaderCacheHolder:rerun", "--initialize-at-run-time" + Seq( + "com.typesafe.config.impl.ConfigImpl", + "com.typesafe.config.impl.ConfigImpl$EnvVariablesHolder", + "com.typesafe.config.impl.ConfigImpl$SystemPropertiesHolder", + "com.typesafe.config.impl.ConfigImpl$LoaderCacheHolder", + "akka.actor.ActorCell", // Do not initialize the actor system until runtime (native-image) // These are to make up for the lack of shaded configuration for svm/native-image in grpc-netty-shaded "com.sun.jndi.dns.DnsClient", "com.typesafe.sslconfig.ssl.tracing.TracingSSLContext", @@ -378,32 +411,30 @@ lazy val `proxy-core` = (project in file("proxy/core")) "io.grpc" % "grpc-netty-shaded" % GrpcJavaVersion, // Since we exclude Aeron, we also exclude its transitive Agrona dependency, so we need to manually add it HERE "org.agrona" % "agrona" % "0.9.29", - "com.typesafe.akka" %% "akka-remote" % AkkaVersion excludeAll (excludeTheseDependencies: _*), + akkaDependency("akka-remote"), + "com.typesafe.akka" %% "akka-protobuf-v390" % (AkkaVersion + "-proto390") excludeAll (excludeTheseDependencies: _*), // FIXME since akka-protobuf-v3 uses a shaded protobuf-java 3.10.0 which is not supported in native-image yet… // For Eventing support of Google Pubsub "com.google.api.grpc" % "grpc-google-cloud-pubsub-v1" % "0.12.0" % "protobuf", // ApacheV2 "io.grpc" % "grpc-auth" % GrpcJavaVersion, // ApacheV2 "com.google.auth" % "google-auth-library-oauth2-http" % "0.15.0", // BSD 3-clause - "com.typesafe.akka" %% "akka-persistence" % AkkaVersion, - "com.typesafe.akka" %% "akka-persistence-query" % AkkaVersion, - "com.typesafe.akka" %% "akka-stream" % AkkaVersion, - "com.typesafe.akka" %% "akka-slf4j" % AkkaVersion, - "com.typesafe.akka" %% "akka-discovery" % AkkaVersion, - "com.typesafe.akka" %% "akka-http" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http-core" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http2-support" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-cluster-sharding" % AkkaVersion excludeAll ((excludeTheseDependencies :+ ExclusionRule( - "org.lmdbjava", - "lmdbjava" - )): _*), - "com.lightbend.akka.management" %% "akka-management-cluster-bootstrap" % AkkaManagementVersion excludeAll (excludeTheseDependencies: _*), - "com.lightbend.akka.discovery" %% "akka-discovery-kubernetes-api" % AkkaManagementVersion excludeAll (excludeTheseDependencies: _*), + akkaDependency("akka-persistence"), + akkaDependency("akka-persistence-query"), + akkaDependency("akka-stream"), + akkaDependency("akka-slf4j"), + akkaDependency("akka-discovery"), + akkaHttpDependency("akka-http"), + akkaHttpDependency("akka-http-spray-json"), + akkaHttpDependency("akka-http-core"), + akkaHttpDependency("akka-http2-support"), + akkaDependency("akka-cluster-sharding", ExclusionRule("org.lmdbjava", "lmdbjava")), + akkaManagementDependency("akka-management-cluster-bootstrap"), + akkaDiscoveryDependency("akka-discovery-kubernetes-api"), "com.google.protobuf" % "protobuf-java" % ProtobufVersion % "protobuf", "com.google.protobuf" % "protobuf-java-util" % ProtobufVersion, "org.scalatest" %% "scalatest" % ScalaTestVersion % Test, - "com.typesafe.akka" %% "akka-testkit" % AkkaVersion % Test, - "com.typesafe.akka" %% "akka-stream-testkit" % AkkaVersion % Test, - "com.typesafe.akka" %% "akka-http-testkit" % AkkaHttpVersion % Test, + akkaDependency("akka-testkit") % Test, + akkaDependency("akka-stream-testkit") % Test, + akkaHttpDependency("akka-http-testkit") % Test, "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf", "io.prometheus" % "simpleclient" % PrometheusClientVersion, "io.prometheus" % "simpleclient_common" % PrometheusClientVersion, @@ -428,21 +459,12 @@ lazy val `proxy-core` = (project in file("proxy/core")) // For Google Cloud Pubsub API PB.protoSources in Compile += target.value / "protobuf_external" / "google" / "pubsub" / "v1", javaAgents += "org.mortbay.jetty.alpn" % "jetty-alpn-agent" % "2.0.9" % "runtime;test", + mainClass in Compile := Some("io.cloudstate.proxy.CloudStateProxyMain"), dockerSettings, fork in run := true, // In memory journal by default javaOptions in run ++= Seq("-Dconfig.resource=dev-mode.conf"), - mainClass in assembly := Some("io.cloudstate.proxy.CloudStateProxyMain"), - assemblyJarName in assembly := "akka-proxy.jar", - test in assembly := {}, - // logLevel in assembly := Level.Debug, - assemblyMergeStrategy in assembly := { - /*ADD CUSTOMIZATIONS HERE*/ - case PathList("META-INF", "io.netty.versions.properties") => MergeStrategy.last - case x => - val oldStrategy = (assemblyMergeStrategy in assembly).value - oldStrategy(x) - }, + assemblySettings("akka-proxy.jar"), nativeImageDockerSettings ) @@ -453,10 +475,8 @@ lazy val `proxy-cassandra` = (project in file("proxy/cassandra")) common, name := "cloudstate-proxy-cassandra", libraryDependencies ++= Seq( - "com.typesafe.akka" %% "akka-persistence-cassandra" % AkkaPersistenceCassandraVersion excludeAll ( - (excludeTheseDependencies :+ ExclusionRule("com.github.jnr")): _* // Can't native-image this, so we don't need this either - ), - "com.typesafe.akka" %% "akka-persistence-cassandra-launcher" % AkkaPersistenceCassandraVersion % Test + akkaPersistenceCassandraDependency("akka-persistence-cassandra", ExclusionRule("com.github.jnr")), + akkaPersistenceCassandraDependency("akka-persistence-cassandra-launcher") % Test ), fork in run := true, mainClass in Compile := Some("io.cloudstate.proxy.CloudStateProxyMain"), @@ -491,17 +511,7 @@ lazy val `proxy-postgres` = (project in file("proxy/postgres")) mainClass in Compile := Some("io.cloudstate.proxy.jdbc.CloudStateJdbcProxyMain"), // If run by sbt, run in dev mode javaOptions in run += "-Dcloudstate.proxy.dev-mode-enabled=true", - mainClass in assembly := (mainClass in Compile).value, - assemblyJarName in assembly := "akka-proxy-postgres.jar", - test in assembly := {}, - // logLevel in assembly := Level.Debug, - assemblyMergeStrategy in assembly := { - /*ADD CUSTOMIZATIONS HERE*/ - case PathList("META-INF", "io.netty.versions.properties") => MergeStrategy.last - case x => - val oldStrategy = (assemblyMergeStrategy in assembly).value - oldStrategy(x) - }, + assemblySettings("akka-proxy.jar"), nativeImageDockerSettings, graalVMNativeImageOptions ++= Seq( "--initialize-at-build-time" @@ -522,7 +532,7 @@ lazy val `proxy-tests` = (project in file("proxy/proxy-tests")) baseDirectory in Test := (baseDirectory in ThisBuild).value, libraryDependencies ++= Seq( "org.scalatest" %% "scalatest" % ScalaTestVersion % Test, - "com.typesafe.akka" %% "akka-testkit" % AkkaVersion % Test + akkaDependency("akka-testkit") % Test ) ) @@ -534,9 +544,9 @@ lazy val operator = (project in file("operator")) common, name := "cloudstate-operator", libraryDependencies ++= Seq( - "com.typesafe.akka" %% "akka-stream" % AkkaVersion, - "com.typesafe.akka" %% "akka-slf4j" % AkkaVersion, - "com.typesafe.akka" %% "akka-http" % AkkaHttpVersion, + akkaDependency("akka-stream"), + akkaDependency("akka-slf4j"), + akkaHttpDependency("akka-http"), "io.skuber" %% "skuber" % "2.4.0", "ch.qos.logback" % "logback-classic" % "1.2.3" // Doesn't work well with SubstrateVM, use "org.slf4j" % "slf4j-simple" % "1.7.26" instead ), @@ -585,19 +595,19 @@ lazy val `java-support` = (project in file("java-support")) // Remove these explicit gRPC/netty dependencies once akka-grpc 0.7.1 is released and we've upgraded to using that "io.grpc" % "grpc-core" % GrpcJavaVersion, "io.grpc" % "grpc-netty-shaded" % GrpcJavaVersion, - "com.typesafe.akka" %% "akka-stream" % AkkaVersion, - "com.typesafe.akka" %% "akka-slf4j" % AkkaVersion, - "com.typesafe.akka" %% "akka-discovery" % AkkaVersion, - "com.typesafe.akka" %% "akka-http" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http-core" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http2-support" % AkkaHttpVersion, + akkaDependency("akka-stream"), + akkaDependency("akka-slf4j"), + akkaDependency("akka-discovery"), + akkaHttpDependency("akka-http"), + akkaHttpDependency("akka-http-spray-json"), + akkaHttpDependency("akka-http-core"), + akkaHttpDependency("akka-http2-support"), "com.google.protobuf" % "protobuf-java" % ProtobufVersion % "protobuf", "com.google.protobuf" % "protobuf-java-util" % ProtobufVersion, "org.scalatest" %% "scalatest" % ScalaTestVersion % Test, - "com.typesafe.akka" %% "akka-testkit" % AkkaVersion % Test, - "com.typesafe.akka" %% "akka-stream-testkit" % AkkaVersion % Test, - "com.typesafe.akka" %% "akka-http-testkit" % AkkaHttpVersion % Test, + akkaDependency("akka-testkit") % Test, + akkaDependency("akka-stream-testkit") % Test, + akkaHttpDependency("akka-http-testkit") % Test, "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf", "org.slf4j" % "slf4j-simple" % "1.7.26", "com.fasterxml.jackson.core" % "jackson-databind" % "2.9.9.3" @@ -664,19 +674,19 @@ lazy val `scala-support` = (project in file("scala-support")) // Remove these explicit gRPC/netty dependencies once akka-grpc 0.7.1 is released and we've upgraded to using that "io.grpc" % "grpc-core" % GrpcJavaVersion, "io.grpc" % "grpc-netty-shaded" % GrpcJavaVersion, - "com.typesafe.akka" %% "akka-stream" % AkkaVersion, - "com.typesafe.akka" %% "akka-slf4j" % AkkaVersion, - "com.typesafe.akka" %% "akka-discovery" % AkkaVersion, - "com.typesafe.akka" %% "akka-http" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http-core" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http2-support" % AkkaHttpVersion, + akkaDependency("akka-stream"), + akkaDependency("akka-slf4j"), + akkaDependency("akka-discovery"), + akkaHttpDependency("akka-http"), + akkaHttpDependency("akka-http-spray-json"), + akkaHttpDependency("akka-http-core"), + akkaHttpDependency("akka-http2-support"), "com.google.protobuf" % "protobuf-java" % ProtobufVersion % "protobuf", "com.google.protobuf" % "protobuf-java-util" % ProtobufVersion, "org.scalatest" %% "scalatest" % ScalaTestVersion % Test, - "com.typesafe.akka" %% "akka-testkit" % AkkaVersion % Test, - "com.typesafe.akka" %% "akka-stream-testkit" % AkkaVersion % Test, - "com.typesafe.akka" %% "akka-http-testkit" % AkkaHttpVersion % Test, + akkaDependency("akka-testkit") % Test, + akkaDependency("akka-stream-testkit") % Test, + akkaHttpDependency("akka-http-testkit") % Test, "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf", "org.slf4j" % "slf4j-simple" % "1.7.26", "com.fasterxml.jackson.core" % "jackson-databind" % "2.9.9.3" @@ -715,17 +725,7 @@ lazy val `java-shopping-cart` = (project in file("samples/java-shopping-cart")) PB.gens.java -> (sourceManaged in Compile).value ), javacOptions in Compile ++= Seq("-encoding", "UTF-8", "-source", "1.8", "-target", "1.8"), - mainClass in assembly := (mainClass in Compile).value, - assemblyJarName in assembly := "java-shopping-cart.jar", - test in assembly := {}, - // logLevel in assembly := Level.Debug, - assemblyMergeStrategy in assembly := { - /*ADD CUSTOMIZATIONS HERE*/ - case PathList("META-INF", "io.netty.versions.properties") => MergeStrategy.last - case x => - val oldStrategy = (assemblyMergeStrategy in assembly).value - oldStrategy(x) - } + assemblySettings("java-shopping-cart.jar") ) lazy val `java-pingpong` = (project in file("samples/java-pingpong")) @@ -745,17 +745,7 @@ lazy val `java-pingpong` = (project in file("samples/java-pingpong")) PB.gens.java -> (sourceManaged in Compile).value ), javacOptions in Compile ++= Seq("-encoding", "UTF-8", "-source", "1.8", "-target", "1.8"), - mainClass in assembly := (mainClass in Compile).value, - assemblyJarName in assembly := "java-pingpong.jar", - test in assembly := {}, - // logLevel in assembly := Level.Debug, - assemblyMergeStrategy in assembly := { - /*ADD CUSTOMIZATIONS HERE*/ - case PathList("META-INF", "io.netty.versions.properties") => MergeStrategy.last - case x => - val oldStrategy = (assemblyMergeStrategy in assembly).value - oldStrategy(x) - } + assemblySettings("java-pingpong.jar") ) lazy val `scala-shopping-cart` = (project in file("samples/scala-shopping-cart")) @@ -769,17 +759,7 @@ lazy val `scala-shopping-cart` = (project in file("samples/scala-shopping-cart") val baseDir = (baseDirectory in ThisBuild).value / "protocols" Seq(baseDir / "frontend", baseDir / "example") }, - mainClass in assembly := Some("io.cloudstate.samples.shoppingcart.Main"), - assemblyJarName in assembly := "scala-shopping-cart.jar", - test in assembly := {}, - // logLevel in assembly := Level.Debug, - assemblyMergeStrategy in assembly := { - /*ADD CUSTOMIZATIONS HERE*/ - case PathList("META-INF", "io.netty.versions.properties") => MergeStrategy.last - case x => - val oldStrategy = (assemblyMergeStrategy in assembly).value - oldStrategy(x) - } + assemblySettings("scala-shopping-cart.jar") ) lazy val `akka-client` = (project in file("samples/akka-client")) @@ -792,13 +772,13 @@ lazy val `akka-client` = (project in file("samples/akka-client")) // Remove these explicit gRPC/netty dependencies once akka-grpc 0.7.1 is released and we've upgraded to using that "io.grpc" % "grpc-netty-shaded" % GrpcJavaVersion, "io.grpc" % "grpc-core" % GrpcJavaVersion, - "com.typesafe.akka" %% "akka-persistence" % AkkaVersion, - "com.typesafe.akka" %% "akka-stream" % AkkaVersion, - "com.typesafe.akka" %% "akka-discovery" % AkkaVersion, - "com.typesafe.akka" %% "akka-http" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http-core" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http2-support" % AkkaHttpVersion, + akkaDependency("akka-persistence"), + akkaDependency("akka-stream"), + akkaDependency("akka-discovery"), + akkaHttpDependency("akka-http"), + akkaHttpDependency("akka-http-spray-json"), + akkaHttpDependency("akka-http-core"), + akkaHttpDependency("akka-http2-support"), "com.google.protobuf" % "protobuf-java" % ProtobufVersion % "protobuf", "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion % "protobuf" ), @@ -830,13 +810,13 @@ lazy val `tck` = (project in file("tck")) // Remove these explicit gRPC/netty dependencies once akka-grpc 0.7.1 is released and we've upgraded to using that "io.grpc" % "grpc-netty-shaded" % GrpcJavaVersion, "io.grpc" % "grpc-core" % GrpcJavaVersion, - "com.typesafe.akka" %% "akka-stream" % AkkaVersion, - "com.typesafe.akka" %% "akka-discovery" % AkkaVersion, - "com.typesafe.akka" %% "akka-http" % AkkaHttpVersion, - "com.typesafe.akka" %% "akka-http-spray-json" % AkkaHttpVersion, + akkaDependency("akka-stream"), + akkaDependency("akka-discovery"), + akkaHttpDependency("akka-http"), + akkaHttpDependency("akka-http-spray-json"), "com.google.protobuf" % "protobuf-java" % ProtobufVersion % "protobuf", "org.scalatest" %% "scalatest" % ScalaTestVersion, - "com.typesafe.akka" %% "akka-testkit" % AkkaVersion + akkaDependency("akka-testkit") ), PB.protoSources in Compile ++= { val baseDir = (baseDirectory in ThisBuild).value / "protocols" @@ -853,13 +833,13 @@ lazy val `graal-tools` = (project in file("graal-tools")) .enablePlugins(GraalVMPlugin) .settings( libraryDependencies ++= List( - "org.graalvm.nativeimage" % "svm" % GraalVersion, + "org.graalvm.nativeimage" % "svm" % GraalVersion % "provided", // Adds configuration to let Graal Native Image (SubstrateVM) work + "com.typesafe.akka" %% "akka-protobuf-v390" % (AkkaVersion + "-proto390") excludeAll (excludeTheseDependencies: _*), "com.github.vmencik" %% "graal-akka-actor" % GraalAkkaVersion, "com.github.vmencik" %% "graal-akka-stream" % GraalAkkaVersion, "com.github.vmencik" %% "graal-akka-http" % GraalAkkaVersion, - "com.typesafe.akka" %% "akka-actor" % AkkaVersion, - "com.typesafe.akka" %% "akka-protobuf" % AkkaVersion, + akkaDependency("akka-actor"), "com.google.protobuf" % "protobuf-java" % ProtobufVersion, "com.thesamet.scalapb" %% "scalapb-runtime" % scalapb.compiler.Version.scalapbVersion ) diff --git a/graal-tools/src/main/java/io/cloudstate/graaltools/Substitutions.java b/graal-tools/src/main/java/io/cloudstate/graaltools/Substitutions.java index 602c3a416..326e89cd7 100644 --- a/graal-tools/src/main/java/io/cloudstate/graaltools/Substitutions.java +++ b/graal-tools/src/main/java/io/cloudstate/graaltools/Substitutions.java @@ -42,43 +42,6 @@ final class Target_io_netty_util_internal_PlatformDependent0 { private static long ADDRESS_FIELD_OFFSET; } -@TargetClass( - className = - "io.grpc.netty.shaded.io.netty.util.internal.shaded.org.jctools.util.UnsafeRefArrayAccess") -final -class Target_io_grpc_netty_shaded_io_netty_util_internal_shaded_org_jctools_util_UnsafeRefArrayAccess { - @Alias - @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.ArrayIndexShift, declClass = Object[].class) - public static int REF_ELEMENT_SHIFT; -} - -@TargetClass(className = "io.grpc.netty.shaded.io.netty.util.internal.CleanerJava6") -final class Target_io_grpc_netty_shaded_io_netty_util_internal_CleanerJava6 { - @Alias - @RecomputeFieldValue( - kind = RecomputeFieldValue.Kind.FieldOffset, - declClassName = "java.nio.DirectByteBuffer", - name = "cleaner") - private static long CLEANER_FIELD_OFFSET; -} - -@TargetClass(className = "io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent") -final class Target_io_grpc_netty_shaded_io_netty_util_internal_PlatformDependent { - @Alias - @RecomputeFieldValue(kind = RecomputeFieldValue.Kind.ArrayBaseOffset, declClass = byte[].class) - private static long BYTE_ARRAY_BASE_OFFSET; -} - -@TargetClass(className = "io.grpc.netty.shaded.io.netty.util.internal.PlatformDependent0") -final class Target_io_grpc_netty_shaded_io_netty_util_internal_PlatformDependent0 { - @Alias - @RecomputeFieldValue( - kind = RecomputeFieldValue.Kind.FieldOffset, - declClassName = "java.nio.Buffer", - name = "address") - private static long ADDRESS_FIELD_OFFSET; -} - @TargetClass(className = "org.agrona.concurrent.AbstractConcurrentArrayQueue") final class Target_org_agrona_concurrent_AbstractConcurrentArrayQueue { @Alias diff --git a/graal-tools/src/main/scala/io/cloudstate/graaltools/AkkaSerializerRegisterFeature.scala b/graal-tools/src/main/scala/io/cloudstate/graaltools/AkkaSerializerRegisterFeature.scala deleted file mode 100644 index eec088420..000000000 --- a/graal-tools/src/main/scala/io/cloudstate/graaltools/AkkaSerializerRegisterFeature.scala +++ /dev/null @@ -1,66 +0,0 @@ -package io.cloudstate.graaltools - -import com.oracle.svm.core.annotate.AutomaticFeature -import org.graalvm.nativeimage.hosted.Feature.QueryReachabilityAccess -import org.graalvm.nativeimage.hosted.{Feature, RuntimeReflection} - -import scala.collection.JavaConverters._ -import java.lang.reflect.Modifier.isAbstract -import java.util.concurrent.ConcurrentHashMap - -@AutomaticFeature -final class AkkaSerializerRegisterFeature extends Feature { - private[this] final val cache = ConcurrentHashMap.newKeySet[String] - - // FIXME THIS IS CURRENTLY DISABLED SINCE IT WILL NOT MERGE ALL REFERENCE CONFS FOR SOME REASON - override final def isInConfiguration(access: Feature.IsInConfigurationAccess): Boolean = false - override final def duringAnalysis(access: Feature.DuringAnalysisAccess): Unit = { - val serializerClass = access.findClassByName(classOf[akka.serialization.Serializer].getName) - if (access.isReachable(serializerClass)) { - val config = com.typesafe.config.ConfigFactory.load(serializerClass.getClassLoader) - config - .getConfig("akka.actor.serializers") - .root - .unwrapped - .values - .iterator - .asScala - .map(_.toString) - .filter(className => !cache.contains(className)) - .foreach(className => registerSerializerClassByName(access, className)) - com.typesafe.config.ConfigFactory.invalidateCaches() - } - } - - override final def afterAnalysis(access: Feature.AfterAnalysisAccess): Unit = - com.typesafe.config.ConfigFactory.invalidateCaches() - - final def registerSerializerClassByName(access: Feature.DuringAnalysisAccess, className: String): Unit = - registerSerializerClass(access, access.findClassByName(className)) - - final def registerSerializerClass(access: Feature.DuringAnalysisAccess, cls: Class[_]): Unit = - for { - cls <- Option(cls).filter(access.isReachable) - if cls != null && !cls.isInterface && !isAbstract(cls.getModifiers) && cache.add(cls.getName) - ctor <- getDeclaredConstructor(cls, classOf[akka.actor.ExtendedActorSystem]) orElse getDeclaredConstructor( - cls - ) - _ = println("Automatically registering serializer class for reflection purposes: " + cls.getName) - } { - RuntimeReflection.register(cls) - RuntimeReflection.register(ctor) - } - - final def registerSubtypesOf(access: Feature.DuringAnalysisAccess, className: String): Unit = { - val akkaSerializerClass = access.findClassByName(className) - if (akkaSerializerClass != null && access.isReachable(akkaSerializerClass)) { - access.reachableSubtypes(akkaSerializerClass).iterator.asScala.filter(_ != null).foreach { subtype => - registerSerializerClass(access, subtype) - } - } - } - - private[this] final def getDeclaredConstructor(cls: Class[_], parameterTypes: Class[_]*) = - try Option(cls.getDeclaredConstructor(parameterTypes: _*)) - catch { case _: NoSuchMethodException => None } -} diff --git a/graal-tools/src/main/scala/io/cloudstate/graaltools/ProtobufGeneratedMessageRegisterFeature.scala b/graal-tools/src/main/scala/io/cloudstate/graaltools/ProtobufGeneratedMessageRegisterFeature.scala index d08ca8593..b8d367e51 100644 --- a/graal-tools/src/main/scala/io/cloudstate/graaltools/ProtobufGeneratedMessageRegisterFeature.scala +++ b/graal-tools/src/main/scala/io/cloudstate/graaltools/ProtobufGeneratedMessageRegisterFeature.scala @@ -11,9 +11,6 @@ import java.util.concurrent.ConcurrentHashMap final class ProtobufGeneratedMessageRegisterFeature extends Feature { private[this] final val cache = ConcurrentHashMap.newKeySet[String] final val messageClasses = Vector( - classOf[akka.protobuf.GeneratedMessage], - classOf[akka.protobuf.GeneratedMessage.Builder[_]], - classOf[akka.protobuf.ProtocolMessageEnum], classOf[com.google.protobuf.GeneratedMessageV3], classOf[com.google.protobuf.GeneratedMessageV3.Builder[_]], classOf[com.google.protobuf.ProtocolMessageEnum], diff --git a/project/GraalVMPlugin.scala b/project/GraalVMPlugin.scala index 0fcdf7111..51fafe028 100644 --- a/project/GraalVMPlugin.scala +++ b/project/GraalVMPlugin.scala @@ -366,10 +366,8 @@ object GraalVMPlugin extends AutoPlugin { if (dep.data.isFile) Some(dep) else { projectArts.find { art => - (art.get(sbt.Keys.artifact.key), dep.get(sbt.Keys.artifact.key)) match { - case (Some(l), Some(r)) => - l.name == r.name && l.classifier == r.classifier - case _ => false + art.get(sbt.Keys.artifact.key).zip(dep.get(sbt.Keys.artifact.key)) exists { + case (l, r) => l.name == r.name && l.classifier == r.classifier } } } diff --git a/proxy/core/src/graal/META-INF/native-image/com.typesafe.akka/akka-actor/reflect-config.json.conf b/proxy/core/src/graal/META-INF/native-image/com.typesafe.akka/akka-actor/reflect-config.json.conf index 19c18156a..27f37b5e8 100644 --- a/proxy/core/src/graal/META-INF/native-image/com.typesafe.akka/akka-actor/reflect-config.json.conf +++ b/proxy/core/src/graal/META-INF/native-image/com.typesafe.akka/akka-actor/reflect-config.json.conf @@ -269,6 +269,9 @@ name: "akka.serialization.SerializationExtension$" fields: [{name: "MODULE$"}] } +{ + name: "akka.serialization.Serialization" +} { name: "akka.util.ByteString$ByteString1" } @@ -279,19 +282,66 @@ name: "akka.util.ByteString$ByteStrings" } { - name: "akka.serialization.NullSerializer$" - allDeclaredConstructors: true + name: "akka.serialization.NullSerializer$" + allDeclaredConstructors: true +} +{ + name: "akka.serialization.JavaSerializer" + allDeclaredConstructors: true +} +{ + name: "akka.serialization.BooleanSerializer" + allDeclaredConstructors: true +} +{ + name: "java.util.concurrent.TimeoutException" } { - name: "akka.serialization.JavaSerializer" - allDeclaredConstructors: true + name: "scala.Boolean" } { - name: "akka.serialization.BooleanSerializer" - allDeclaredConstructors: true + name: "java.lang.Boolean" } { - name: "akka.serialization.ByteArraySerializer" - allDeclaredConstructors: true + name: "akka.serialization.ByteArraySerializer" + allDeclaredConstructors: true +} +{ + name: "akka.serialization.IntSerializer" + allDeclaredConstructors: true +} +{ + name: "akka.serialization.LongSerializer" + allDeclaredConstructors: true +} +{ + name: "akka.serialization.StringSerializer" + allDeclaredConstructors: true +} +{ + name: "akka.serialization.ByteStringSerializer" + allDeclaredConstructors: true +} +{ + name: "akka.serialization.DisabledJavaSerializer" + allDeclaredConstructors: true +} +{ + name: "java.lang.Throwable" +} +{ + name: "akka.actor.Address" +} +{ + name: "akka.Done" +} +{ + name: "akka.NotUsed" +} +{ + name: "akka.actor.PoisonPill$" +} +{ + name: "akka.actor.Kill$" } ] diff --git a/proxy/core/src/graal/META-INF/native-image/com.typesafe.akka/akka-remote/reflect-config.json.conf b/proxy/core/src/graal/META-INF/native-image/com.typesafe.akka/akka-remote/reflect-config.json.conf index 984f11ee0..3a7beb04f 100644 --- a/proxy/core/src/graal/META-INF/native-image/com.typesafe.akka/akka-remote/reflect-config.json.conf +++ b/proxy/core/src/graal/META-INF/native-image/com.typesafe.akka/akka-remote/reflect-config.json.conf @@ -11,6 +11,9 @@ allDeclaredFields: true allDeclaredConstructors: true } +{ + name: "akka.remote.RemoteWatcher$Heartbeat$" +} { name: "akka.remote.RemoteScope" } @@ -69,4 +72,11 @@ name: "akka.remote.serialization.IntSerializer" allDeclaredConstructors: true } +{ + name: "akka.remote.serialization.ThrowableNotSerializableException" +} +{ + name: "akka.remote.UniqueAddress" +} + ] diff --git a/proxy/core/src/graal/META-INF/native-image/com.typesafe.akka/akka-stream/reflect-config.json.conf b/proxy/core/src/graal/META-INF/native-image/com.typesafe.akka/akka-stream/reflect-config.json.conf index 0307b7de7..0e2bcec5a 100644 --- a/proxy/core/src/graal/META-INF/native-image/com.typesafe.akka/akka-stream/reflect-config.json.conf +++ b/proxy/core/src/graal/META-INF/native-image/com.typesafe.akka/akka-stream/reflect-config.json.conf @@ -16,6 +16,10 @@ name: "akka.stream.SystemMaterializer" allDeclaredConstructors: true } +{ + name: "akka.stream.SystemMaterializer$" + allDeclaredConstructors: true +} { name: "akka.stream.impl.fusing.ActorGraphInterpreter" allDeclaredFields: true diff --git a/proxy/core/src/graal/META-INF/native-image/com.typesafe/ssl-config/native-image.properties b/proxy/core/src/graal/META-INF/native-image/com.typesafe/ssl-config/native-image.properties new file mode 100644 index 000000000..98d306764 --- /dev/null +++ b/proxy/core/src/graal/META-INF/native-image/com.typesafe/ssl-config/native-image.properties @@ -0,0 +1 @@ +Args = -H:ReflectionConfigurationResources=${.}/reflect-config.json diff --git a/proxy/core/src/graal/META-INF/native-image/com.typesafe/ssl-config/reflect-config.json.conf b/proxy/core/src/graal/META-INF/native-image/com.typesafe/ssl-config/reflect-config.json.conf new file mode 100644 index 000000000..1a3ed0d08 --- /dev/null +++ b/proxy/core/src/graal/META-INF/native-image/com.typesafe/ssl-config/reflect-config.json.conf @@ -0,0 +1,6 @@ +[ + { + "name": "com.typesafe.sslconfig.ssl.NoopHostnameVerifier" + allDeclaredConstructors: true + } +] diff --git a/proxy/core/src/main/resources/cloudstate-common.conf b/proxy/core/src/main/resources/cloudstate-common.conf index 9f47004fe..8102a7613 100644 --- a/proxy/core/src/main/resources/cloudstate-common.conf +++ b/proxy/core/src/main/resources/cloudstate-common.conf @@ -1,8 +1,13 @@ // Common configuration to be included by other impls akka { + // FIXME library-extensions try to add a non-existent akka.stream.SystemMaterializer extension + library-extensions = ["akka.serialization.SerializationExtension"] actor { provider = cluster + allow-java-serialization = off + warn-about-java-serializer-usage = off + internal-dispatcher = akka.actor.default-dispatcher // FIXME consider removing this line serializers { crdt-serializers = "io.cloudstate.proxy.crdt.CrdtSerializers" proto-any = "io.cloudstate.proxy.ProtobufAnySerializer" @@ -39,6 +44,8 @@ akka { artery { enabled = on transport = tcp + // FIXME do we need to set canonical.hostname? + // FIXME do we need to set advanced.tcp.connection-timeout? canonical.port = ${?REMOTING_PORT} bind.port = ${?REMOTING_PORT} } @@ -47,16 +54,17 @@ akka { cluster { shutdown-after-unsuccessful-join-seed-nodes = 60s + // FIXME consider settin distributed-data.max-delta-elements = + // FIXME consider setting distributed-data.delta-crdt.max-delta-size = + sharding.state-store-mode = ddata // Non-durable for now, since we can't get native-image to work with lmdb right now sharding.distributed-data.durable.keys = [] - // fixme Of course, this is not ideal, but not much choice at the moment. - auto-down-unreachable-after = 30s - sharding { rebalance-interval = 5s + passivate-idle-entity-after = off // FIXME put in a good value here } // Native image doesn't support JMX diff --git a/proxy/core/src/main/scala/io/cloudstate/proxy/CloudStateProxyMain.scala b/proxy/core/src/main/scala/io/cloudstate/proxy/CloudStateProxyMain.scala index 840286f8b..34fee0fcc 100644 --- a/proxy/core/src/main/scala/io/cloudstate/proxy/CloudStateProxyMain.scala +++ b/proxy/core/src/main/scala/io/cloudstate/proxy/CloudStateProxyMain.scala @@ -27,7 +27,7 @@ import akka.cluster.Cluster import akka.management.cluster.bootstrap.ClusterBootstrap import akka.management.scaladsl.AkkaManagement import akka.pattern.{BackoffOpts, BackoffSupervisor} -import akka.stream.ActorMaterializer +import akka.stream.SystemMaterializer import org.slf4j.LoggerFactory import sun.misc.Signal @@ -140,7 +140,7 @@ object CloudStateProxyMain { } implicit val system = configuration.fold(ActorSystem("cloudstate-proxy"))(c => ActorSystem("cloudstate-proxy", c)) - implicit val materializer = ActorMaterializer() + implicit val materializer = SystemMaterializer(system) import system.dispatcher val c = system.settings.config.getConfig("cloudstate.proxy") diff --git a/proxy/core/src/main/scala/io/cloudstate/proxy/EntityDiscoveryManager.scala b/proxy/core/src/main/scala/io/cloudstate/proxy/EntityDiscoveryManager.scala index 409f370e4..27ee4dc8b 100644 --- a/proxy/core/src/main/scala/io/cloudstate/proxy/EntityDiscoveryManager.scala +++ b/proxy/core/src/main/scala/io/cloudstate/proxy/EntityDiscoveryManager.scala @@ -31,7 +31,7 @@ import akka.cluster.singleton.{ ClusterSingletonProxySettings } import akka.grpc.GrpcClientSettings -import akka.stream.ActorMaterializer +import akka.stream.Materializer import com.google.protobuf.DescriptorProtos import com.google.protobuf.Descriptors.{FileDescriptor, ServiceDescriptor} import com.typesafe.config.Config @@ -119,7 +119,7 @@ object EntityDiscoveryManager { } } - def props(config: Configuration)(implicit mat: ActorMaterializer): Props = + def props(config: Configuration)(implicit mat: Materializer): Props = Props(new EntityDiscoveryManager(config)) final case object Ready // Responds with true / false @@ -138,7 +138,7 @@ object EntityDiscoveryManager { } class EntityDiscoveryManager(config: EntityDiscoveryManager.Configuration)( - implicit mat: ActorMaterializer + implicit mat: Materializer ) extends Actor with ActorLogging { diff --git a/proxy/core/src/main/scala/io/cloudstate/proxy/eventing/EventingManager.scala b/proxy/core/src/main/scala/io/cloudstate/proxy/eventing/EventingManager.scala index cea584073..c3ec5de77 100644 --- a/proxy/core/src/main/scala/io/cloudstate/proxy/eventing/EventingManager.scala +++ b/proxy/core/src/main/scala/io/cloudstate/proxy/eventing/EventingManager.scala @@ -2,7 +2,7 @@ package io.cloudstate.proxy.eventing import akka.{Done, NotUsed} import akka.actor.Cancellable -import akka.stream.{ActorMaterializer, FlowShape, OverflowStrategy} +import akka.stream.{FlowShape, Materializer, OverflowStrategy} import akka.stream.scaladsl.{Flow, GraphDSL, Merge, Partition, RunnableGraph, Sink, Source} import io.cloudstate.protocol.entity.{ClientAction, EntityDiscoveryClient, Failure, Reply, UserFunctionError} import io.cloudstate.proxy.{Serve, UserFunctionRouter} @@ -71,7 +71,7 @@ object EventingManager { else List(EventMapping(entity, endpoints)) } - def createSupport(eventConfig: Config)(implicit materializer: ActorMaterializer): Option[EventingSupport] = + def createSupport(eventConfig: Config)(implicit materializer: Materializer): Option[EventingSupport] = eventConfig.getString("support") match { case "none" => log.info("Eventing support turned off in configuration") diff --git a/proxy/core/src/main/scala/io/cloudstate/proxy/eventing/GooglePubsubEventing.scala b/proxy/core/src/main/scala/io/cloudstate/proxy/eventing/GooglePubsubEventing.scala index ed76392ed..20efb7820 100644 --- a/proxy/core/src/main/scala/io/cloudstate/proxy/eventing/GooglePubsubEventing.scala +++ b/proxy/core/src/main/scala/io/cloudstate/proxy/eventing/GooglePubsubEventing.scala @@ -4,7 +4,7 @@ import com.typesafe.config.{Config, ConfigFactory} import akka.NotUsed import akka.actor.{ActorSystem, Cancellable} import akka.grpc.GrpcClientSettings -import akka.stream.ActorMaterializer +import akka.stream.Materializer import akka.stream.scaladsl.{Flow, Keep, Sink, Source} import io.cloudstate.proxy.Serve.CommandHandler import io.cloudstate.proxy.EntityDiscoveryManager.ServableEntity @@ -136,7 +136,7 @@ object GCPubsubEventingSupport { final val USING_CRD = "using-crd" } -class GCPubsubEventingSupport(config: Config, materializer: ActorMaterializer) extends EventingSupport { +class GCPubsubEventingSupport(config: Config, materializer: Materializer) extends EventingSupport { import GCPubsubEventingSupport._ final val projectId: String = config.getString("project-id") diff --git a/tck/src/it/resources/application.conf b/tck/src/it/resources/application.conf index 57cd222b8..9b39deb10 100644 --- a/tck/src/it/resources/application.conf +++ b/tck/src/it/resources/application.conf @@ -44,8 +44,8 @@ cloudstate-tck.combinations = [{ hostname = "127.0.0.1" port = 9000 directory = ${user.dir} - //command = ["java","-Xmx512M", "-Xms128M", "-Dconfig.resource=in-memory.conf", "-Dcloudstate.proxy.dev-mode-enabled=true", "-jar", "proxy/core/target/scala-2.12/akka-proxy.jar"] - command = ["proxy/core/target/graalvm-native-image/cloudstate-proxy-core", "-Djava.library.path="${JAVA_HOME}"/lib", "-Dconfig.resource=in-memory.conf", "-Dcloudstate.proxy.dev-mode-enabled=true"] + command = ["java","-Xmx512M", "-Xms128M", "-Dconfig.resource=in-memory.conf", "-Dcloudstate.proxy.dev-mode-enabled=true", "-jar", "proxy/core/target/scala-2.12/akka-proxy.jar"] + //command = ["proxy/core/target/graalvm-native-image/cloudstate-proxy-core", "-Djava.library.path="${JAVA_HOME}"/lib", "-Dconfig.resource=in-memory.conf", "-Dcloudstate.proxy.dev-mode-enabled=true"] env-vars { USER_FUNCTION_PORT = "8090" diff --git a/tck/src/it/scala/io/cloudstate/tck/TCK.scala b/tck/src/it/scala/io/cloudstate/tck/TCK.scala index 6c68000a0..c85fd0f1f 100644 --- a/tck/src/it/scala/io/cloudstate/tck/TCK.scala +++ b/tck/src/it/scala/io/cloudstate/tck/TCK.scala @@ -21,6 +21,6 @@ class TCK extends Suites({ iterator. asScala. filter(section => verify(section.getString("name"))). - map(c => new CloudStateTCK(CloudStateTCK.Configuration(c))). + map(c => new CloudStateTCK(TckConfiguration.fromConfig(c))). toVector }: _*) with SequentialNestedSuiteExecution diff --git a/tck/src/main/resources/reference.conf b/tck/src/main/resources/reference.conf index d2c7a4790..6d7e2ad6e 100644 --- a/tck/src/main/resources/reference.conf +++ b/tck/src/main/resources/reference.conf @@ -1,4 +1,9 @@ cloudstate-tck { + #verify is a list of names of combinations to run for the TCK + verify = [] + #combinations is a list of config objects with a name, a proxy, and a frontend + combinations = [] + tck { hostname = "127.0.0.1" hostname = ${?HOST}