From a6eda00f8857d86297518acd575fa1a7c9f0c1d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Johan=20Andr=C3=A9n?= Date: Tue, 2 Dec 2025 14:58:00 +0100 Subject: [PATCH 1/4] build: MiMa latest patch of 2.10 (#32854) --- project/MiMa.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/MiMa.scala b/project/MiMa.scala index efd95528394..b959974c4a3 100644 --- a/project/MiMa.scala +++ b/project/MiMa.scala @@ -22,7 +22,7 @@ object MiMa extends AutoPlugin { private val firstPatchOf29 = 0 private val latestPatchOf29 = 8 private val firstPatchOf210 = 0 - private val latestPatchOf210 = 12 + private val latestPatchOf210 = 13 override def requires = MimaPlugin override def trigger = allRequirements From faaa7cb5174cb178bddd68b76083b0bf4780ea79 Mon Sep 17 00:00:00 2001 From: Sebastian Alfers Date: Wed, 3 Dec 2025 17:29:28 +0100 Subject: [PATCH 2/4] chore: switch to at.yawk.lz4 (#32856) --- project/Dependencies.scala | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/project/Dependencies.scala b/project/Dependencies.scala index 325917aae4f..d878484de5b 100644 --- a/project/Dependencies.scala +++ b/project/Dependencies.scala @@ -84,7 +84,7 @@ object Dependencies { val jacksonScala = "com.fasterxml.jackson.module" %% "jackson-module-scala" % jacksonCoreVersion // ApacheV2 val jacksonParameterNames = "com.fasterxml.jackson.module" % "jackson-module-parameter-names" % jacksonCoreVersion // ApacheV2 val jacksonCbor = "com.fasterxml.jackson.dataformat" % "jackson-dataformat-cbor" % jacksonCoreVersion // ApacheV2 - val lz4Java = "org.lz4" % "lz4-java" % "1.8.0" // ApacheV2 + val lz4Java = "at.yawk.lz4" % "lz4-java" % "1.10.0" // ApacheV2 val logback = "ch.qos.logback" % "logback-classic" % logbackVersion // EPL 1.0 } From b954655b8d057adb3aa2fbcd9e0177c2e82ed133 Mon Sep 17 00:00:00 2001 From: Patrik Nordwall Date: Thu, 4 Dec 2025 10:21:19 +0100 Subject: [PATCH 3/4] chore: Harden ShardedDaemonProcessRescaleSpec (#32855) * couldn't use the receptionist group router because it sometimes dropped messages, probably some init race condition * using a singleton instead --- .../ShardedDaemonProcessRescaleSpec.scala | 118 +++++++++++------- 1 file changed, 76 insertions(+), 42 deletions(-) diff --git a/akka-cluster-sharding-typed/src/multi-jvm/scala/akka/cluster/sharding/typed/ShardedDaemonProcessRescaleSpec.scala b/akka-cluster-sharding-typed/src/multi-jvm/scala/akka/cluster/sharding/typed/ShardedDaemonProcessRescaleSpec.scala index 4e47b184874..f0f96aaaa0d 100644 --- a/akka-cluster-sharding-typed/src/multi-jvm/scala/akka/cluster/sharding/typed/ShardedDaemonProcessRescaleSpec.scala +++ b/akka-cluster-sharding-typed/src/multi-jvm/scala/akka/cluster/sharding/typed/ShardedDaemonProcessRescaleSpec.scala @@ -7,19 +7,22 @@ package akka.cluster.sharding.typed import scala.concurrent.duration._ import com.typesafe.config.ConfigFactory +import org.scalatest.concurrent.Eventually import org.scalatest.concurrent.ScalaFutures +import org.scalatest.time.Span +import akka.Done import akka.actor.testkit.typed.scaladsl.TestProbe import akka.actor.typed.ActorRef +import akka.actor.typed.ActorSystem import akka.actor.typed.Behavior -import akka.actor.typed.receptionist.Receptionist -import akka.actor.typed.receptionist.ServiceKey import akka.actor.typed.scaladsl.Behaviors -import akka.actor.typed.scaladsl.Routers import akka.actor.typed.scaladsl.adapter.ClassicActorSystemOps import akka.cluster.MultiNodeClusterSpec import akka.cluster.sharding.typed.scaladsl.ShardedDaemonProcess +import akka.cluster.typed.ClusterSingleton import akka.cluster.typed.MultiNodeTypedClusterSpec +import akka.cluster.typed.SingletonActor import akka.pattern.StatusReply import akka.remote.testkit.MultiNodeConfig import akka.remote.testkit.MultiNodeSpec @@ -34,28 +37,57 @@ object ShardedDaemonProcessRescaleSpec extends MultiNodeConfig { val sixth = role("sixth") val seventh = role("seventh") - val SnitchServiceKey = ServiceKey[AnyRef]("snitch") - case class ProcessActorEvent(id: Int, event: Any) extends CborSerializable object ProcessActor { trait Command case object Stop extends Command - def apply(id: Int): Behavior[Command] = Behaviors.setup { ctx => + def apply(id: Int, collector: ActorRef[Collector.Command]): Behavior[Command] = Behaviors.setup { ctx => ctx.log.info("Started [{}]", id) - val snitchRouter = ctx.spawn(Routers.group(SnitchServiceKey), "router") - snitchRouter ! ProcessActorEvent(id, "Started") + collector ! Collector.Started(id) Behaviors.receiveMessagePartial { case Stop => ctx.log.info("Stopped [{}]", id) - snitchRouter ! ProcessActorEvent(id, "Stopped") + collector ! Collector.Stopped(id) Behaviors.stopped } } } + object Collector { + sealed trait Command extends CborSerializable + final case class Started(id: Int) extends Command + final case class Stopped(id: Int) extends Command + final case class Get(replyTo: ActorRef[Counts]) extends Command + final case class Counts(startedCount: Int, stoppedCount: Int) extends CborSerializable + final case class Reset(replyTo: ActorRef[Done]) extends Command + + def init(system: ActorSystem[_]): ActorRef[Command] = { + ClusterSingleton(system).init(SingletonActor(Collector(), "collector")) + } + + def apply(): Behavior[Command] = { + behavior(Counts(startedCount = 0, stoppedCount = 0)) + } + + private def behavior(counts: Counts): Behavior[Command] = { + Behaviors.receiveMessage { + case Started(_) => + behavior(counts.copy(startedCount = counts.startedCount + 1)) + case Stopped(_) => + behavior(counts.copy(stoppedCount = counts.stoppedCount + 1)) + case Get(replyTo) => + replyTo ! counts + Behaviors.same + case Reset(replyTo) => + replyTo ! Done + behavior(Counts(0, 0)) + } + } + } + commonConfig( ConfigFactory.parseString(""" akka.loglevel = DEBUG @@ -89,12 +121,19 @@ class ShardedDaemonProcessRescaleMultiJvmNode7 extends ShardedDaemonProcessResca abstract class ShardedDaemonProcessRescaleSpec extends MultiNodeSpec(ShardedDaemonProcessRescaleSpec) with MultiNodeTypedClusterSpec - with ScalaFutures { + with ScalaFutures + with Eventually { import ShardedDaemonProcessRescaleSpec._ - val topicProbe: TestProbe[AnyRef] = TestProbe[AnyRef]() + implicit val patience: PatienceConfig = { + import akka.testkit.TestDuration + PatienceConfig(testKitSettings.DefaultTimeout.duration.dilated * 2, Span(500, org.scalatest.time.Millis)) + } + private var sdp: ActorRef[ShardedDaemonProcessCommand] = _ + private var collector: ActorRef[Collector.Command] = _ + private val resetProbe = TestProbe[Done]() private def assertNumberOfProcesses(n: Int, revision: Int): Unit = { val probe = TestProbe[NumberOfProcesses]() @@ -108,35 +147,23 @@ abstract class ShardedDaemonProcessRescaleSpec "Cluster sharding in multi dc cluster" must { "form cluster" in { formCluster(first, second, third, fourth, fifth, sixth, seventh) - runOn(first) { - typedSystem.receptionist ! Receptionist.Register(SnitchServiceKey, topicProbe.ref, topicProbe.ref) - topicProbe.expectMessageType[Receptionist.Registered] - } - enterBarrier("snitch-registered") - topicProbe.awaitAssert({ - typedSystem.receptionist ! Receptionist.Find(SnitchServiceKey, topicProbe.ref) - topicProbe.expectMessageType[Receptionist.Listing].serviceInstances(SnitchServiceKey).size should ===(1) - }, 5.seconds) - enterBarrier("snitch-seen") + collector = Collector.init(system.toTyped) + enterBarrier("collector-started") } "init actor set" in { sdp = ShardedDaemonProcess(typedSystem).initWithContext( "the-fearless", 4, - ctx => ProcessActor(ctx.processNumber), + ctx => ProcessActor(ctx.processNumber, collector), ShardedDaemonProcessSettings(system.toTyped), ProcessActor.Stop) enterBarrier("sharded-daemon-process-initialized") - runOn(first) { - val startedIds = (0 to 3).map { _ => - val event = topicProbe.expectMessageType[ProcessActorEvent](5.seconds) - event.event should ===("Started") - event.id - }.toSet - startedIds.size should ===(4) - topicProbe.expectNoMessage() + eventually { + val countsReplyProbe = TestProbe[Collector.Counts]() + collector ! Collector.Get(countsReplyProbe.ref) + countsReplyProbe.expectMessage(500.millis, Collector.Counts(startedCount = 4, stoppedCount = 0)) } enterBarrier("sharded-daemon-process-started-acked") runOn(third) { @@ -147,14 +174,18 @@ abstract class ShardedDaemonProcessRescaleSpec "rescale to 8 workers" in { runOn(first) { + collector ! Collector.Reset(resetProbe.ref) + resetProbe.expectMessage(Done) + val probe = TestProbe[AnyRef]() sdp ! ChangeNumberOfProcesses(8, probe.ref) probe.expectMessage(30.seconds, StatusReply.Ack) -// FIXME snitch router is dropping messages -// val events = topicProbe.receiveMessages(4 + 8, 10.seconds).map(_.asInstanceOf[ProcessActorEvent]) -// events.collect { case evt if evt.event == "Stopped" => evt.id }.toSet.size should ===(4) -// events.collect { case evt if evt.event == "Started" => evt.id }.toSet.size should ===(8) -// topicProbe.expectNoMessage() + } + enterBarrier("sharded-daemon-process-rescaled-to-8") + eventually { + val countsReplyProbe = TestProbe[Collector.Counts]() + collector ! Collector.Get(countsReplyProbe.ref) + countsReplyProbe.expectMessage(500.millis, Collector.Counts(startedCount = 8, stoppedCount = 4)) } enterBarrier("sharded-daemon-process-rescaled-to-8-acked") @@ -166,18 +197,21 @@ abstract class ShardedDaemonProcessRescaleSpec "rescale to 2 workers" in { runOn(second) { + collector ! Collector.Reset(resetProbe.ref) + resetProbe.expectMessage(Done) + val probe = TestProbe[AnyRef]() sdp ! ChangeNumberOfProcesses(2, probe.ref) probe.expectMessage(30.seconds, StatusReply.Ack) } - enterBarrier("sharded-daemon-process-rescaled-to-2-acked") - runOn(first) { -// FIXME snitch router is dropping messages -// val events = topicProbe.receiveMessages(8 + 2, 10.seconds).map(_.asInstanceOf[ProcessActorEvent]) -// events.collect { case evt if evt.event == "Stopped" => evt.id }.toSet.size should ===(8) -// events.collect { case evt if evt.event == "Started" => evt.id }.toSet.size should ===(2) -// topicProbe.expectNoMessage() + enterBarrier("sharded-daemon-process-rescaled-to-2") + eventually { + val countsReplyProbe = TestProbe[Collector.Counts]() + collector ! Collector.Get(countsReplyProbe.ref) + countsReplyProbe.expectMessage(500.millis, Collector.Counts(startedCount = 2, stoppedCount = 8)) } + + enterBarrier("sharded-daemon-process-rescaled-to-2-acked") runOn(third) { assertNumberOfProcesses(n = 2, revision = 2) } From c6b63fef123be6d3165ff76d00d229ad2753a415 Mon Sep 17 00:00:00 2001 From: Sebastian Alfers Date: Thu, 4 Dec 2025 11:16:45 +0100 Subject: [PATCH 4/4] chore: License change and sample bump for 2.10.14 (#32860) --- LICENSE | 4 ++-- samples/akka-quickstart-java/build.gradle | 4 ++-- samples/akka-quickstart-java/pom.xml | 2 +- samples/akka-quickstart-scala/build.sbt | 2 +- samples/akka-sample-cluster-java/build.sbt | 2 +- samples/akka-sample-cluster-java/pom.xml | 2 +- samples/akka-sample-cluster-scala/build.sbt | 2 +- samples/akka-sample-distributed-data-java/build.sbt | 2 +- samples/akka-sample-distributed-data-java/pom.xml | 2 +- samples/akka-sample-distributed-data-scala/build.sbt | 2 +- samples/akka-sample-fsm-java/pom.xml | 2 +- samples/akka-sample-fsm-scala/build.sbt | 2 +- samples/akka-sample-kafka-to-sharding-scala/build.sbt | 2 +- samples/akka-sample-sharding-java/build.sbt | 2 +- samples/akka-sample-sharding-java/killrweather-fog/pom.xml | 2 +- samples/akka-sample-sharding-java/killrweather/pom.xml | 2 +- samples/akka-sample-sharding-scala/build.sbt | 2 +- 17 files changed, 19 insertions(+), 19 deletions(-) diff --git a/LICENSE b/LICENSE index ada2c927baf..4b9107b7b2a 100644 --- a/LICENSE +++ b/LICENSE @@ -3,7 +3,7 @@ Business Source License 1.1 Parameters Licensor: Lightbend, Inc. -Licensed Work: Akka 2.10.13 +Licensed Work: Akka 2.10.14 This license applies to all sub directories and files UNLESS another license file is present in a sub directory, then that other license applies to all files @@ -19,7 +19,7 @@ Additional Use Grant: Connecting to a Play Framework websocket and/or Play Framework request/response bodies for server and play-ws client. -Change Date: 2028-12-02 +Change Date: 2028-12-04 Change License: Apache License, Version 2.0 diff --git a/samples/akka-quickstart-java/build.gradle b/samples/akka-quickstart-java/build.gradle index 05171696f70..c6fad6e30ce 100644 --- a/samples/akka-quickstart-java/build.gradle +++ b/samples/akka-quickstart-java/build.gradle @@ -9,9 +9,9 @@ repositories { } dependencies { - implementation 'com.typesafe.akka:akka-actor-typed_2.13:2.10.13' + implementation 'com.typesafe.akka:akka-actor-typed_2.13:2.10.14' implementation 'ch.qos.logback:logback-classic:1.2.13' - testImplementation 'com.typesafe.akka:akka-actor-testkit-typed_2.13:2.10.13' + testImplementation 'com.typesafe.akka:akka-actor-testkit-typed_2.13:2.10.14' testImplementation 'junit:junit:4.13.1' } diff --git a/samples/akka-quickstart-java/pom.xml b/samples/akka-quickstart-java/pom.xml index 9b1953f5c10..bbdf41cfb7b 100644 --- a/samples/akka-quickstart-java/pom.xml +++ b/samples/akka-quickstart-java/pom.xml @@ -6,7 +6,7 @@ 1.0 - 2.10.13 + 2.10.14 diff --git a/samples/akka-quickstart-scala/build.sbt b/samples/akka-quickstart-scala/build.sbt index 8aae1e91867..3dc785a53f6 100644 --- a/samples/akka-quickstart-scala/build.sbt +++ b/samples/akka-quickstart-scala/build.sbt @@ -4,7 +4,7 @@ version := "1.0" scalaVersion := "2.13.17" -lazy val akkaVersion = sys.props.getOrElse("akka.version", "2.10.13") +lazy val akkaVersion = sys.props.getOrElse("akka.version", "2.10.14") // Run in a separate JVM, to make sure sbt waits until all threads have // finished before returning. diff --git a/samples/akka-sample-cluster-java/build.sbt b/samples/akka-sample-cluster-java/build.sbt index a252f7b322a..32aaf18de5f 100644 --- a/samples/akka-sample-cluster-java/build.sbt +++ b/samples/akka-sample-cluster-java/build.sbt @@ -1,7 +1,7 @@ import com.typesafe.sbt.SbtMultiJvm.multiJvmSettings import com.typesafe.sbt.SbtMultiJvm.MultiJvmKeys.MultiJvm -val AkkaVersion = "2.10.13" +val AkkaVersion = "2.10.14" val AkkaDiagnosticsVersion = "2.1.0" val LogbackClassicVersion = "1.2.11" val ScalaTestVersion = "3.1.1" diff --git a/samples/akka-sample-cluster-java/pom.xml b/samples/akka-sample-cluster-java/pom.xml index 420457c3d63..9e4c049a605 100644 --- a/samples/akka-sample-cluster-java/pom.xml +++ b/samples/akka-sample-cluster-java/pom.xml @@ -11,7 +11,7 @@ UTF-8 - 2.10.13 + 2.10.14 2.1.0 diff --git a/samples/akka-sample-cluster-scala/build.sbt b/samples/akka-sample-cluster-scala/build.sbt index 67210d0601d..653b2b749c2 100644 --- a/samples/akka-sample-cluster-scala/build.sbt +++ b/samples/akka-sample-cluster-scala/build.sbt @@ -1,7 +1,7 @@ import com.typesafe.sbt.SbtMultiJvm.multiJvmSettings import com.typesafe.sbt.SbtMultiJvm.MultiJvmKeys.MultiJvm -val AkkaVersion = "2.10.13" +val AkkaVersion = "2.10.14" val AkkaDiagnosticsVersion = "2.1.1" val LogbackClassicVersion = "1.5.18" val ScalaTestVersion = "3.2.17" diff --git a/samples/akka-sample-distributed-data-java/build.sbt b/samples/akka-sample-distributed-data-java/build.sbt index 8fe89de47e3..f23bb8fd20f 100644 --- a/samples/akka-sample-distributed-data-java/build.sbt +++ b/samples/akka-sample-distributed-data-java/build.sbt @@ -1,7 +1,7 @@ import com.typesafe.sbt.SbtMultiJvm.multiJvmSettings import com.typesafe.sbt.SbtMultiJvm.MultiJvmKeys.MultiJvm -val AkkaVersion = "2.10.13" +val AkkaVersion = "2.10.14" val AkkaDiagnosticsVersion = "2.1.0" val LogbackClassicVersion = "1.2.11" val ScalaTestVersion = "3.1.1" diff --git a/samples/akka-sample-distributed-data-java/pom.xml b/samples/akka-sample-distributed-data-java/pom.xml index ee46c1f6f51..d84b02bc82a 100644 --- a/samples/akka-sample-distributed-data-java/pom.xml +++ b/samples/akka-sample-distributed-data-java/pom.xml @@ -11,7 +11,7 @@ UTF-8 - 2.10.13 + 2.10.14 2.1.0 diff --git a/samples/akka-sample-distributed-data-scala/build.sbt b/samples/akka-sample-distributed-data-scala/build.sbt index 1bbc558e92c..24ca2da753e 100644 --- a/samples/akka-sample-distributed-data-scala/build.sbt +++ b/samples/akka-sample-distributed-data-scala/build.sbt @@ -1,6 +1,6 @@ import com.typesafe.sbt.MultiJvmPlugin.multiJvmSettings -val AkkaVersion = "2.10.13" +val AkkaVersion = "2.10.14" val AkkaDiagnosticsVersion = "2.1.1" val LogbackClassicVersion = "1.5.18" val ScalaTestVersion = "3.2.17" diff --git a/samples/akka-sample-fsm-java/pom.xml b/samples/akka-sample-fsm-java/pom.xml index eaab5ef5cd7..064571c8ff0 100644 --- a/samples/akka-sample-fsm-java/pom.xml +++ b/samples/akka-sample-fsm-java/pom.xml @@ -6,7 +6,7 @@ UTF-8 - 2.10.13 + 2.10.14 2.1.0 diff --git a/samples/akka-sample-fsm-scala/build.sbt b/samples/akka-sample-fsm-scala/build.sbt index 09168ae947b..54db20ad9b4 100644 --- a/samples/akka-sample-fsm-scala/build.sbt +++ b/samples/akka-sample-fsm-scala/build.sbt @@ -1,7 +1,7 @@ organization := "com.lightbend.akka.samples" name := "akka-sample-fsm-scala" -val AkkaVersion = "2.10.13" +val AkkaVersion = "2.10.14" val LogbackClassicVersion = "1.5.1" val AkkaDiagnosticsVersion = "2.1.0" diff --git a/samples/akka-sample-kafka-to-sharding-scala/build.sbt b/samples/akka-sample-kafka-to-sharding-scala/build.sbt index 9a988c859ac..56a969b5c09 100644 --- a/samples/akka-sample-kafka-to-sharding-scala/build.sbt +++ b/samples/akka-sample-kafka-to-sharding-scala/build.sbt @@ -1,4 +1,4 @@ -val AkkaVersion = "2.10.13" +val AkkaVersion = "2.10.14" val AlpakkaKafkaVersion = "7.0.1" val AkkaManagementVersion = "1.6.0" val AkkaHttpVersion = "10.7.0" diff --git a/samples/akka-sample-sharding-java/build.sbt b/samples/akka-sample-sharding-java/build.sbt index cd3300ed427..960ca30ed1f 100644 --- a/samples/akka-sample-sharding-java/build.sbt +++ b/samples/akka-sample-sharding-java/build.sbt @@ -1,5 +1,5 @@ -val AkkaVersion = "2.10.13" +val AkkaVersion = "2.10.14" val AkkaHttpVersion = "10.7.0" val LogbackVersion = "1.2.11" diff --git a/samples/akka-sample-sharding-java/killrweather-fog/pom.xml b/samples/akka-sample-sharding-java/killrweather-fog/pom.xml index 14fb2f986b5..e8872ca2d43 100644 --- a/samples/akka-sample-sharding-java/killrweather-fog/pom.xml +++ b/samples/akka-sample-sharding-java/killrweather-fog/pom.xml @@ -18,7 +18,7 @@ UTF-8 - 2.10.13 + 2.10.14 10.7.0 2.1.0 diff --git a/samples/akka-sample-sharding-java/killrweather/pom.xml b/samples/akka-sample-sharding-java/killrweather/pom.xml index 5edc4177ff5..02f74fcdcc0 100644 --- a/samples/akka-sample-sharding-java/killrweather/pom.xml +++ b/samples/akka-sample-sharding-java/killrweather/pom.xml @@ -18,7 +18,7 @@ UTF-8 - 2.10.13 + 2.10.14 10.7.0 2.1.0 diff --git a/samples/akka-sample-sharding-scala/build.sbt b/samples/akka-sample-sharding-scala/build.sbt index 7a474a275bc..3e8cb803baa 100644 --- a/samples/akka-sample-sharding-scala/build.sbt +++ b/samples/akka-sample-sharding-scala/build.sbt @@ -1,4 +1,4 @@ -val AkkaVersion = "2.10.13" +val AkkaVersion = "2.10.14" val AkkaHttpVersion = "10.7.1" val AkkaDiagnostics = "2.2.1" val LogbackVersion = "1.5.18"