Merge branch 'master' into wip-traversal-oriented-layout-master-patriknw
This commit is contained in:
commit
3554ad7243
25 changed files with 313 additions and 64 deletions
|
|
@ -652,7 +652,7 @@ akka {
|
||||||
# `akka.actor.serialization-identifiers."FQCN" = ID`
|
# `akka.actor.serialization-identifiers."FQCN" = ID`
|
||||||
# where `FQCN` is fully qualified class name of the serializer implementation
|
# where `FQCN` is fully qualified class name of the serializer implementation
|
||||||
# and `ID` is globally unique serializer identifier number.
|
# and `ID` is globally unique serializer identifier number.
|
||||||
# Identifier values from 0 to 16 are reserved for Akka internal usage.
|
# Identifier values from 0 to 40 are reserved for Akka internal usage.
|
||||||
serialization-identifiers {
|
serialization-identifiers {
|
||||||
"akka.serialization.JavaSerializer" = 1
|
"akka.serialization.JavaSerializer" = 1
|
||||||
"akka.serialization.ByteArraySerializer" = 4
|
"akka.serialization.ByteArraySerializer" = 4
|
||||||
|
|
|
||||||
|
|
@ -5,13 +5,14 @@
|
||||||
package akka.actor.dungeon
|
package akka.actor.dungeon
|
||||||
|
|
||||||
import scala.annotation.tailrec
|
import scala.annotation.tailrec
|
||||||
import akka.dispatch.{ Mailbox, Envelope }
|
import akka.dispatch.{ Envelope, Mailbox }
|
||||||
import akka.dispatch.sysmsg._
|
import akka.dispatch.sysmsg._
|
||||||
import akka.event.Logging.Error
|
import akka.event.Logging.Error
|
||||||
import akka.util.Unsafe
|
import akka.util.Unsafe
|
||||||
import akka.actor._
|
import akka.actor._
|
||||||
import akka.serialization.SerializationExtension
|
import akka.serialization.SerializationExtension
|
||||||
import scala.util.control.NonFatal
|
|
||||||
|
import scala.util.control.{ NoStackTrace, NonFatal }
|
||||||
import scala.util.control.Exception.Catcher
|
import scala.util.control.Exception.Catcher
|
||||||
import akka.dispatch.MailboxType
|
import akka.dispatch.MailboxType
|
||||||
import akka.dispatch.ProducesMessageQueue
|
import akka.dispatch.ProducesMessageQueue
|
||||||
|
|
@ -106,7 +107,11 @@ private[akka] trait Dispatch { this: ActorCell ⇒
|
||||||
system.eventStream.publish(Error(e, self.path.toString, clazz(actor), "interrupted during message send"))
|
system.eventStream.publish(Error(e, self.path.toString, clazz(actor), "interrupted during message send"))
|
||||||
Thread.currentThread.interrupt()
|
Thread.currentThread.interrupt()
|
||||||
case NonFatal(e) ⇒
|
case NonFatal(e) ⇒
|
||||||
system.eventStream.publish(Error(e, self.path.toString, clazz(actor), "swallowing exception during message send"))
|
val message = e match {
|
||||||
|
case n: NoStackTrace ⇒ "swallowing exception during message send: " + n.getMessage
|
||||||
|
case _ ⇒ "swallowing exception during message send" // stack trace includes message
|
||||||
|
}
|
||||||
|
system.eventStream.publish(Error(e, self.path.toString, clazz(actor), message))
|
||||||
}
|
}
|
||||||
|
|
||||||
// ➡➡➡ NEVER SEND THE SAME SYSTEM MESSAGE OBJECT TO TWO ACTORS ⬅⬅⬅
|
// ➡➡➡ NEVER SEND THE SAME SYSTEM MESSAGE OBJECT TO TWO ACTORS ⬅⬅⬅
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ trait Serializer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Completely unique value to identify this implementation of Serializer, used to optimize network traffic.
|
* Completely unique value to identify this implementation of Serializer, used to optimize network traffic.
|
||||||
* Values from 0 to 16 are reserved for Akka internal usage.
|
* Values from 0 to 40 are reserved for Akka internal usage.
|
||||||
*/
|
*/
|
||||||
def identifier: Int
|
def identifier: Int
|
||||||
|
|
||||||
|
|
@ -105,7 +105,7 @@ abstract class SerializerWithStringManifest extends Serializer {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Completely unique value to identify this implementation of Serializer, used to optimize network traffic.
|
* Completely unique value to identify this implementation of Serializer, used to optimize network traffic.
|
||||||
* Values from 0 to 16 are reserved for Akka internal usage.
|
* Values from 0 to 40 are reserved for Akka internal usage.
|
||||||
*/
|
*/
|
||||||
def identifier: Int
|
def identifier: Int
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,47 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2014-2017 Lightbend Inc. <http://www.lightbend.com>
|
||||||
|
*/
|
||||||
|
|
||||||
|
package akka.stream
|
||||||
|
|
||||||
|
import java.util.concurrent.TimeUnit
|
||||||
|
|
||||||
|
import akka.actor.ActorSystem
|
||||||
|
import akka.stream.scaladsl._
|
||||||
|
import akka.{ Done, NotUsed }
|
||||||
|
import org.openjdk.jmh.annotations._
|
||||||
|
|
||||||
|
import scala.concurrent._
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
@State(Scope.Benchmark)
|
||||||
|
@OutputTimeUnit(TimeUnit.MILLISECONDS)
|
||||||
|
@BenchmarkMode(Array(Mode.Throughput))
|
||||||
|
class EmptySourceBenchmark {
|
||||||
|
implicit val system = ActorSystem("EmptySourceBenchmark")
|
||||||
|
val materializerSettings = ActorMaterializerSettings(system).withDispatcher("akka.test.stream-dispatcher")
|
||||||
|
implicit val materializer = ActorMaterializer(materializerSettings)
|
||||||
|
|
||||||
|
|
||||||
|
@TearDown
|
||||||
|
def shutdown(): Unit = {
|
||||||
|
Await.result(system.terminate(), 5.seconds)
|
||||||
|
}
|
||||||
|
|
||||||
|
val setup = Source.empty[String].toMat(Sink.ignore)(Keep.right)
|
||||||
|
|
||||||
|
@Benchmark def empty(): Unit =
|
||||||
|
Await.result(setup.run(), Duration.Inf)
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
(not serious benchmark, just sanity check: run on macbook 15, late 2013)
|
||||||
|
|
||||||
|
While it was a PublisherSource:
|
||||||
|
[info] EmptySourceBenchmark.empty thrpt 10 11.219 ± 6.498 ops/ms
|
||||||
|
|
||||||
|
Rewrite to GraphStage:
|
||||||
|
[info] EmptySourceBenchmark.empty thrpt 10 17.556 ± 2.865 ops/ms
|
||||||
|
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
@ -144,3 +144,72 @@ If you get the error "unknown locale: UTF-8" when generating the documentation t
|
||||||
export LANG=en_US.UTF-8
|
export LANG=en_US.UTF-8
|
||||||
export LC_ALL=en_US.UTF-8
|
export LC_ALL=en_US.UTF-8
|
||||||
|
|
||||||
|
Installing Sphinx on Linux
|
||||||
|
--------------------------
|
||||||
|
Install Python with your package manager:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
apt-get install python # for Debian based systems
|
||||||
|
yum install python # for CentOS/RHEL systems
|
||||||
|
|
||||||
|
This will automatically add Python executable to your $PATH and pip is a part of the default Python installation. Remember you need `sudo` rights to run this command.
|
||||||
|
|
||||||
|
More information in case of trouble:
|
||||||
|
https://packaging.python.org/install_requirements_linux/
|
||||||
|
|
||||||
|
Install Sphinx:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
apt-get install python-sphinx # for Debian based systems
|
||||||
|
#alternatively
|
||||||
|
pip install sphinx
|
||||||
|
|
||||||
|
For other Linux systems please check Sphinx website:
|
||||||
|
http://www.sphinx-doc.org/en/stable/install.html#other-linux-distributions
|
||||||
|
|
||||||
|
Install TextLive:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
apt-get install texlive-latex-base texlive-latex-extra texlive-latex-recommended
|
||||||
|
# additionally you may need xzdec
|
||||||
|
apt-get install xzdec
|
||||||
|
|
||||||
|
In case you get the following error:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Unknown directive ...containerchecksum c59200574a316416a23695c258edf3a32531fbda43ccdc09360ee105c3f07f9fb77df17c4ba4c2ea4f3a5ea6667e064b51e3d8c2fe6c984ba3e71b4e32716955... , please fix it! at /usr/share/texlive/tlpkg/TeXLive/TLPOBJ.pm line 210, <$retfh> line 5579.
|
||||||
|
|
||||||
|
you need to specify you want to continue using the 2015 version:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
tlmgr option repository ftp://tug.org/historic/systems/texlive/2015/tlnet-final
|
||||||
|
|
||||||
|
Add missing tex packages:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
sudo tlmgr update --self
|
||||||
|
sudo tlmgr install titlesec
|
||||||
|
sudo tlmgr install framed
|
||||||
|
sudo tlmgr install threeparttable
|
||||||
|
sudo tlmgr install wrapfig
|
||||||
|
sudo tlmgr install helvetic
|
||||||
|
sudo tlmgr install courier
|
||||||
|
sudo tlmgr install multirow
|
||||||
|
sudo tlmgr install capt-of
|
||||||
|
sudo tlmgr install needspace
|
||||||
|
sudo tlmgr install eqparbox
|
||||||
|
sudo tlmgr install environ
|
||||||
|
sudo tlmgr install trimspaces
|
||||||
|
|
||||||
|
If you get the error "unknown locale: UTF-8" when generating the documentation the solution is to define the following environment variables:
|
||||||
|
|
||||||
|
::
|
||||||
|
|
||||||
|
export LANG=en_US.UTF-8
|
||||||
|
export LC_ALL=en_US.UTF-8
|
||||||
|
|
|
||||||
|
|
@ -125,7 +125,7 @@ seed nodes in the existing cluster.
|
||||||
|
|
||||||
If you don't configure seed nodes you need to join the cluster programmatically or manually.
|
If you don't configure seed nodes you need to join the cluster programmatically or manually.
|
||||||
|
|
||||||
Manual joining can be performed by using ref:`cluster_jmx_java` or :ref:`cluster_http_java`.
|
Manual joining can be performed by using :ref:`cluster_jmx_java` or :ref:`cluster_http_java`.
|
||||||
Joining programmatically can be performed with ``Cluster.get(system).join``. Unsuccessful join attempts are
|
Joining programmatically can be performed with ``Cluster.get(system).join``. Unsuccessful join attempts are
|
||||||
automatically retried after the time period defined in configuration property ``retry-unsuccessful-join-after``.
|
automatically retried after the time period defined in configuration property ``retry-unsuccessful-join-after``.
|
||||||
Retries can be disabled by setting the property to ``off``.
|
Retries can be disabled by setting the property to ``off``.
|
||||||
|
|
@ -173,9 +173,9 @@ can be performed automatically or manually. By default it must be done manually,
|
||||||
It can also be performed programmatically with ``Cluster.get(system).down(address)``.
|
It can also be performed programmatically with ``Cluster.get(system).down(address)``.
|
||||||
|
|
||||||
A pre-packaged solution for the downing problem is provided by
|
A pre-packaged solution for the downing problem is provided by
|
||||||
`Split Brain Resolver <http://doc.akka.io/docs/akka/akka-commercial-addons-1.0/java/split-brain-resolver.html>`_,
|
`Split Brain Resolver <http://developer.lightbend.com/docs/akka-commercial-addons/current/split-brain-resolver.html>`_,
|
||||||
which is part of the `Lightbend Reactive Platform <http://www.lightbend.com/platform>`_.
|
which is part of the `Lightbend Reactive Platform <http://www.lightbend.com/platform>`_.
|
||||||
If you don’t use RP, you should anyway carefully read the `documentation <http://doc.akka.io/docs/akka/akka-commercial-addons-1.0/java/split-brain-resolver.html>`_
|
If you don’t use RP, you should anyway carefully read the `documentation <http://developer.lightbend.com/docs/akka-commercial-addons/current/split-brain-resolver.html>`_
|
||||||
of the Split Brain Resolver and make sure that the solution you are using handles the concerns
|
of the Split Brain Resolver and make sure that the solution you are using handles the concerns
|
||||||
described there.
|
described there.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
package docs.remoting;
|
package docs.remoting;
|
||||||
|
|
||||||
import akka.testkit.AkkaJUnitActorSystemResource;
|
import akka.testkit.AkkaJUnitActorSystemResource;
|
||||||
|
import docs.AbstractJavaTest;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
@ -21,7 +22,7 @@ import akka.remote.RemoteScope;
|
||||||
|
|
||||||
import akka.actor.AbstractActor;
|
import akka.actor.AbstractActor;
|
||||||
|
|
||||||
public class RemoteDeploymentDocTest {
|
public class RemoteDeploymentDocTest extends AbstractJavaTest {
|
||||||
|
|
||||||
public static class SampleActor extends AbstractActor {
|
public static class SampleActor extends AbstractActor {
|
||||||
@Override
|
@Override
|
||||||
|
|
|
||||||
|
|
@ -29,7 +29,7 @@ public class SerializationDocTest {
|
||||||
|
|
||||||
// Pick a unique identifier for your Serializer,
|
// Pick a unique identifier for your Serializer,
|
||||||
// you've got a couple of billions to choose from,
|
// you've got a couple of billions to choose from,
|
||||||
// 0 - 16 is reserved by Akka itself
|
// 0 - 40 is reserved by Akka itself
|
||||||
@Override public int identifier() {
|
@Override public int identifier() {
|
||||||
return 1234567;
|
return 1234567;
|
||||||
}
|
}
|
||||||
|
|
@ -80,7 +80,7 @@ public class SerializationDocTest {
|
||||||
|
|
||||||
// Pick a unique identifier for your Serializer,
|
// Pick a unique identifier for your Serializer,
|
||||||
// you've got a couple of billions to choose from,
|
// you've got a couple of billions to choose from,
|
||||||
// 0 - 16 is reserved by Akka itself
|
// 0 - 40 is reserved by Akka itself
|
||||||
@Override public int identifier() {
|
@Override public int identifier() {
|
||||||
return 1234567;
|
return 1234567;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,6 +20,7 @@ import java.util.concurrent.CompletionStage;
|
||||||
import java.util.concurrent.ExecutionException;
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.concurrent.TimeUnit;
|
import java.util.concurrent.TimeUnit;
|
||||||
|
|
||||||
|
import docs.AbstractJavaTest;
|
||||||
import scala.concurrent.duration.Duration;
|
import scala.concurrent.duration.Duration;
|
||||||
//#other-imports
|
//#other-imports
|
||||||
|
|
||||||
|
|
@ -29,7 +30,7 @@ import org.junit.*;
|
||||||
* This class is not meant to be run as a test in the test suite, but it
|
* This class is not meant to be run as a test in the test suite, but it
|
||||||
* is set up such that it can be run interactively from within an IDE.
|
* is set up such that it can be run interactively from within an IDE.
|
||||||
*/
|
*/
|
||||||
public class QuickStartDocTest {
|
public class QuickStartDocTest extends AbstractJavaTest {
|
||||||
|
|
||||||
static
|
static
|
||||||
//#create-materializer
|
//#create-materializer
|
||||||
|
|
|
||||||
|
|
@ -14,10 +14,11 @@ import akka.testkit.TestProbe;
|
||||||
|
|
||||||
import com.typesafe.config.ConfigFactory;
|
import com.typesafe.config.ConfigFactory;
|
||||||
|
|
||||||
|
import docs.AbstractJavaTest;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class ParentChildTest {
|
public class ParentChildTest extends AbstractJavaTest {
|
||||||
@ClassRule
|
@ClassRule
|
||||||
public static AkkaJUnitActorSystemResource actorSystemResource =
|
public static AkkaJUnitActorSystemResource actorSystemResource =
|
||||||
new AkkaJUnitActorSystemResource("TestKitDocTest",
|
new AkkaJUnitActorSystemResource("TestKitDocTest",
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,8 @@ package docs.testkit;
|
||||||
import static org.junit.Assert.*;
|
import static org.junit.Assert.*;
|
||||||
|
|
||||||
import akka.testkit.*;
|
import akka.testkit.*;
|
||||||
|
import docs.AbstractJavaTest;
|
||||||
|
import org.junit.Assert;
|
||||||
import org.junit.ClassRule;
|
import org.junit.ClassRule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
|
||||||
|
|
@ -24,7 +26,7 @@ import scala.concurrent.Future;
|
||||||
import akka.testkit.TestActor.AutoPilot;
|
import akka.testkit.TestActor.AutoPilot;
|
||||||
import scala.concurrent.duration.Duration;
|
import scala.concurrent.duration.Duration;
|
||||||
|
|
||||||
public class TestKitDocTest {
|
public class TestKitDocTest extends AbstractJavaTest {
|
||||||
|
|
||||||
@ClassRule
|
@ClassRule
|
||||||
public static AkkaJUnitActorSystemResource actorSystemResource =
|
public static AkkaJUnitActorSystemResource actorSystemResource =
|
||||||
|
|
@ -76,7 +78,7 @@ public class TestKitDocTest {
|
||||||
final TestActorRef<MyActor> ref = TestActorRef.create(system, props, "myActor");
|
final TestActorRef<MyActor> ref = TestActorRef.create(system, props, "myActor");
|
||||||
try {
|
try {
|
||||||
ref.receive(new Exception("expected"));
|
ref.receive(new Exception("expected"));
|
||||||
fail("expected an exception to be thrown");
|
Assert.fail("expected an exception to be thrown");
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
assertEquals("expected", e.getMessage());
|
assertEquals("expected", e.getMessage());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@
|
||||||
package docs.testkit;
|
package docs.testkit;
|
||||||
|
|
||||||
//#fullsample
|
//#fullsample
|
||||||
|
import docs.AbstractJavaTest;
|
||||||
import org.junit.AfterClass;
|
import org.junit.AfterClass;
|
||||||
import org.junit.Assert;
|
import org.junit.Assert;
|
||||||
import org.junit.BeforeClass;
|
import org.junit.BeforeClass;
|
||||||
|
|
@ -16,7 +17,7 @@ import akka.actor.AbstractActor;
|
||||||
import akka.testkit.JavaTestKit;
|
import akka.testkit.JavaTestKit;
|
||||||
import scala.concurrent.duration.Duration;
|
import scala.concurrent.duration.Duration;
|
||||||
|
|
||||||
public class TestKitSampleTest {
|
public class TestKitSampleTest extends AbstractJavaTest {
|
||||||
|
|
||||||
public static class SomeActor extends AbstractActor {
|
public static class SomeActor extends AbstractActor {
|
||||||
ActorRef target = null;
|
ActorRef target = null;
|
||||||
|
|
|
||||||
|
|
@ -219,10 +219,10 @@ maximum stash capacity in the mailbox configuration::
|
||||||
|
|
||||||
Note that the stash capacity is per actor. If you have many persistent actors, e.g. when using cluster sharding,
|
Note that the stash capacity is per actor. If you have many persistent actors, e.g. when using cluster sharding,
|
||||||
you may need to define a small stash capacity to ensure that the total number of stashed messages in the system
|
you may need to define a small stash capacity to ensure that the total number of stashed messages in the system
|
||||||
don't consume too much memory. Additionally, The persistent actor defines three strategies to handle failure when the
|
doesn't consume too much memory. Additionally, the persistent actor defines three strategies to handle failure when the
|
||||||
internal stash capacity is exceeded. The default overflow strategy is the ``ThrowOverflowExceptionStrategy``, which
|
internal stash capacity is exceeded. The default overflow strategy is the ``ThrowOverflowExceptionStrategy``, which
|
||||||
discards the current received message and throws a ``StashOverflowException``, causing actor restart if default
|
discards the current received message and throws a ``StashOverflowException``, causing actor restart if the default
|
||||||
supervision strategy is used. you can override the ``internalStashOverflowStrategy`` method to return
|
supervision strategy is used. You can override the ``internalStashOverflowStrategy`` method to return
|
||||||
``DiscardToDeadLetterStrategy`` or ``ReplyToStrategy`` for any "individual" persistent actor, or define the "default"
|
``DiscardToDeadLetterStrategy`` or ``ReplyToStrategy`` for any "individual" persistent actor, or define the "default"
|
||||||
for all persistent actors by providing FQCN, which must be a subclass of ``StashOverflowStrategyConfigurator``, in the
|
for all persistent actors by providing FQCN, which must be a subclass of ``StashOverflowStrategyConfigurator``, in the
|
||||||
persistence configuration::
|
persistence configuration::
|
||||||
|
|
@ -233,7 +233,7 @@ persistence configuration::
|
||||||
The ``DiscardToDeadLetterStrategy`` strategy also has a pre-packaged companion configurator
|
The ``DiscardToDeadLetterStrategy`` strategy also has a pre-packaged companion configurator
|
||||||
``akka.persistence.DiscardConfigurator``.
|
``akka.persistence.DiscardConfigurator``.
|
||||||
|
|
||||||
You can also query default strategy via the Akka persistence extension singleton::
|
You can also query the default strategy via the Akka persistence extension singleton::
|
||||||
|
|
||||||
Persistence.get(getContext().system()).defaultInternalStashOverflowStrategy();
|
Persistence.get(getContext().system()).defaultInternalStashOverflowStrategy();
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ seed nodes in the existing cluster.
|
||||||
|
|
||||||
If you don't configure seed nodes you need to join the cluster programmatically or manually.
|
If you don't configure seed nodes you need to join the cluster programmatically or manually.
|
||||||
|
|
||||||
Manual joining can be performed by using ref:`cluster_jmx_scala` or :ref:`cluster_http_scala`.
|
Manual joining can be performed by using :ref:`cluster_jmx_scala` or :ref:`cluster_http_scala`.
|
||||||
Joining programmatically can be performed with ``Cluster(system).join``. Unsuccessful join attempts are
|
Joining programmatically can be performed with ``Cluster(system).join``. Unsuccessful join attempts are
|
||||||
automatically retried after the time period defined in configuration property ``retry-unsuccessful-join-after``.
|
automatically retried after the time period defined in configuration property ``retry-unsuccessful-join-after``.
|
||||||
Retries can be disabled by setting the property to ``off``.
|
Retries can be disabled by setting the property to ``off``.
|
||||||
|
|
@ -168,9 +168,9 @@ can be performed automatically or manually. By default it must be done manually,
|
||||||
It can also be performed programmatically with ``Cluster(system).down(address)``.
|
It can also be performed programmatically with ``Cluster(system).down(address)``.
|
||||||
|
|
||||||
A pre-packaged solution for the downing problem is provided by
|
A pre-packaged solution for the downing problem is provided by
|
||||||
`Split Brain Resolver <http://doc.akka.io/docs/akka/akka-commercial-addons-1.0/scala/split-brain-resolver.html>`_,
|
`Split Brain Resolver <http://developer.lightbend.com/docs/akka-commercial-addons/current/split-brain-resolver.html>`_,
|
||||||
which is part of the `Lightbend Reactive Platform <http://www.lightbend.com/platform>`_.
|
which is part of the `Lightbend Reactive Platform <http://www.lightbend.com/platform>`_.
|
||||||
If you don’t use RP, you should anyway carefully read the `documentation <http://doc.akka.io/docs/akka/akka-commercial-addons-1.0/scala/split-brain-resolver.html>`_
|
If you don’t use RP, you should anyway carefully read the `documentation <http://developer.lightbend.com/docs/akka-commercial-addons/current/split-brain-resolver.html>`_
|
||||||
of the Split Brain Resolver and make sure that the solution you are using handles the concerns
|
of the Split Brain Resolver and make sure that the solution you are using handles the concerns
|
||||||
described there.
|
described there.
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -25,7 +25,7 @@ package docs.serialization {
|
||||||
|
|
||||||
// Pick a unique identifier for your Serializer,
|
// Pick a unique identifier for your Serializer,
|
||||||
// you've got a couple of billions to choose from,
|
// you've got a couple of billions to choose from,
|
||||||
// 0 - 16 is reserved by Akka itself
|
// 0 - 40 is reserved by Akka itself
|
||||||
def identifier = 1234567
|
def identifier = 1234567
|
||||||
|
|
||||||
// "toBinary" serializes the given object to an Array of Bytes
|
// "toBinary" serializes the given object to an Array of Bytes
|
||||||
|
|
@ -58,7 +58,7 @@ package docs.serialization {
|
||||||
|
|
||||||
// Pick a unique identifier for your Serializer,
|
// Pick a unique identifier for your Serializer,
|
||||||
// you've got a couple of billions to choose from,
|
// you've got a couple of billions to choose from,
|
||||||
// 0 - 16 is reserved by Akka itself
|
// 0 - 40 is reserved by Akka itself
|
||||||
def identifier = 1234567
|
def identifier = 1234567
|
||||||
|
|
||||||
// The manifest (type hint) that will be provided in the fromBinary method
|
// The manifest (type hint) that will be provided in the fromBinary method
|
||||||
|
|
|
||||||
|
|
@ -108,8 +108,8 @@ class TwitterStreamQuickstartDocSpec extends AkkaSpec {
|
||||||
|
|
||||||
trait HiddenDefinitions {
|
trait HiddenDefinitions {
|
||||||
//#graph-dsl-broadcast
|
//#graph-dsl-broadcast
|
||||||
val writeAuthors: Sink[Author, Unit] = ???
|
val writeAuthors: Sink[Author, NotUsed] = ???
|
||||||
val writeHashtags: Sink[Hashtag, Unit] = ???
|
val writeHashtags: Sink[Hashtag, NotUsed] = ???
|
||||||
//#graph-dsl-broadcast
|
//#graph-dsl-broadcast
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -218,10 +218,10 @@ maximum stash capacity in the mailbox configuration::
|
||||||
|
|
||||||
Note that the stash capacity is per actor. If you have many persistent actors, e.g. when using cluster sharding,
|
Note that the stash capacity is per actor. If you have many persistent actors, e.g. when using cluster sharding,
|
||||||
you may need to define a small stash capacity to ensure that the total number of stashed messages in the system
|
you may need to define a small stash capacity to ensure that the total number of stashed messages in the system
|
||||||
don't consume too much memory. Additionally, The persistent actor defines three strategies to handle failure when the
|
doesn't consume too much memory. Additionally, the persistent actor defines three strategies to handle failure when the
|
||||||
internal stash capacity is exceeded. The default overflow strategy is the ``ThrowOverflowExceptionStrategy``, which
|
internal stash capacity is exceeded. The default overflow strategy is the ``ThrowOverflowExceptionStrategy``, which
|
||||||
discards the current received message and throws a ``StashOverflowException``, causing actor restart if default
|
discards the current received message and throws a ``StashOverflowException``, causing actor restart if the default
|
||||||
supervision strategy is used. you can override the ``internalStashOverflowStrategy`` method to return
|
supervision strategy is used. You can override the ``internalStashOverflowStrategy`` method to return
|
||||||
``DiscardToDeadLetterStrategy`` or ``ReplyToStrategy`` for any "individual" persistent actor, or define the "default"
|
``DiscardToDeadLetterStrategy`` or ``ReplyToStrategy`` for any "individual" persistent actor, or define the "default"
|
||||||
for all persistent actors by providing FQCN, which must be a subclass of ``StashOverflowStrategyConfigurator``, in the
|
for all persistent actors by providing FQCN, which must be a subclass of ``StashOverflowStrategyConfigurator``, in the
|
||||||
persistence configuration::
|
persistence configuration::
|
||||||
|
|
@ -232,7 +232,7 @@ persistence configuration::
|
||||||
The ``DiscardToDeadLetterStrategy`` strategy also has a pre-packaged companion configurator
|
The ``DiscardToDeadLetterStrategy`` strategy also has a pre-packaged companion configurator
|
||||||
``akka.persistence.DiscardConfigurator``.
|
``akka.persistence.DiscardConfigurator``.
|
||||||
|
|
||||||
You can also query default strategy via the Akka persistence extension singleton::
|
You can also query the default strategy via the Akka persistence extension singleton::
|
||||||
|
|
||||||
Persistence(context.system).defaultInternalStashOverflowStrategy
|
Persistence(context.system).defaultInternalStashOverflowStrategy
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,16 +4,15 @@
|
||||||
|
|
||||||
package akka.remote.serialization
|
package akka.remote.serialization
|
||||||
|
|
||||||
import language.postfixOps
|
import akka.actor.{ Actor, ActorRef, ActorSystem, Address, Deploy, ExtendedActorSystem, OneForOneStrategy, Props, SupervisorStrategy }
|
||||||
import akka.serialization.SerializationExtension
|
|
||||||
import com.typesafe.config.ConfigFactory
|
|
||||||
import akka.testkit.AkkaSpec
|
|
||||||
import akka.actor.{ Actor, ActorRef, Address, Deploy, ExtendedActorSystem, OneForOneStrategy, Props, SupervisorStrategy }
|
|
||||||
import akka.remote.{ DaemonMsgCreate, RemoteScope }
|
import akka.remote.{ DaemonMsgCreate, RemoteScope }
|
||||||
import akka.routing.{ FromConfig, RoundRobinPool }
|
import akka.routing.{ FromConfig, RoundRobinPool }
|
||||||
import akka.util.ByteString
|
import akka.serialization.SerializationExtension
|
||||||
|
import akka.testkit.{ AkkaSpec, TestKit }
|
||||||
|
import com.typesafe.config.ConfigFactory
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
import scala.language.postfixOps
|
||||||
|
|
||||||
object DaemonMsgCreateSerializerSpec {
|
object DaemonMsgCreateSerializerSpec {
|
||||||
|
|
||||||
|
|
@ -81,33 +80,46 @@ class DaemonMsgCreateSerializerSpec extends AkkaSpec {
|
||||||
}
|
}
|
||||||
|
|
||||||
"deserialize the old wire format with just class and field for props parameters (if possible)" in {
|
"deserialize the old wire format with just class and field for props parameters (if possible)" in {
|
||||||
val serializer = new DaemonMsgCreateSerializer(system.asInstanceOf[ExtendedActorSystem])
|
val system = ActorSystem("DaemonMsgCreateSerializer-old-wire-format", ConfigFactory.parseString(
|
||||||
|
"""
|
||||||
|
# in 2.4 this is off by default, but in 2.5+ its on so we wouldn't
|
||||||
|
# get the right set of serializers (and since the old wire protocol doesn't
|
||||||
|
# contain serializer ids that will go unnoticed with unpleasant consequences)
|
||||||
|
akka.actor.enable-additional-serialization-bindings = off
|
||||||
|
"""))
|
||||||
|
|
||||||
// the oldSnapshot was created with the version of DemonMsgCreateSerializer in Akka 2.4.17. See issue #22224.
|
try {
|
||||||
// It was created with:
|
val serializer = new DaemonMsgCreateSerializer(system.asInstanceOf[ExtendedActorSystem])
|
||||||
/*
|
|
||||||
|
// the oldSnapshot was created with the version of DemonMsgCreateSerializer in Akka 2.4.17. See issue #22224.
|
||||||
|
// It was created with:
|
||||||
|
/*
|
||||||
import org.apache.commons.codec.binary.Hex.encodeHex
|
import org.apache.commons.codec.binary.Hex.encodeHex
|
||||||
val bytes = serializer.toBinary(
|
val bytes = serializer.toBinary(
|
||||||
DaemonMsgCreate(Props(classOf[MyActorWithParam], "a string"), Deploy.local, "/user/test", system.actorFor("/user")))
|
DaemonMsgCreate(Props(classOf[MyActorWithParam], "a string"), Deploy.local, "/user/test", system.actorFor("/user")))
|
||||||
println(String.valueOf(encodeHex(bytes)))
|
println(String.valueOf(encodeHex(bytes)))
|
||||||
*/
|
*/
|
||||||
|
|
||||||
val oldBytesHex =
|
val oldBytesHex =
|
||||||
"0a6a12020a001a48616b6b612e72656d6f74652e73657269616c697a6174696f" +
|
"0a7112020a001a48616b6b612e72656d6f74652e73657269616c697a617" +
|
||||||
"6e2e4461656d6f6e4d736743726561746553657269616c697a6572537065632" +
|
"4696f6e2e4461656d6f6e4d736743726561746553657269616c697a6572" +
|
||||||
"44d794163746f7257697468506172616d22086120737472696e672a106a6176" +
|
"53706563244d794163746f7257697468506172616d220faced000574000" +
|
||||||
"612e6c616e672e537472696e67122f0a00222baced000573720016616b6b612" +
|
"86120737472696e672a106a6176612e6c616e672e537472696e67122f0a" +
|
||||||
"e6163746f722e4c6f63616c53636f706524000000000000000102000078701a" +
|
"00222baced000573720016616b6b612e6163746f722e4c6f63616c53636" +
|
||||||
"0a2f757365722f74657374222b0a29616b6b613a2f2f4461656d6f6e4d73674" +
|
"f706524000000000000000102000078701a0a2f757365722f7465737422" +
|
||||||
"3726561746553657269616c697a6572537065632f75736572"
|
"2b0a29616b6b613a2f2f4461656d6f6e4d7367437265617465536572696" +
|
||||||
|
"16c697a6572537065632f75736572"
|
||||||
|
|
||||||
import org.apache.commons.codec.binary.Hex.decodeHex
|
import org.apache.commons.codec.binary.Hex.decodeHex
|
||||||
val oldBytes = decodeHex(oldBytesHex.toCharArray)
|
val oldBytes = decodeHex(oldBytesHex.toCharArray)
|
||||||
val result = serializer.fromBinary(oldBytes, classOf[DaemonMsgCreate])
|
val result = serializer.fromBinary(oldBytes, classOf[DaemonMsgCreate])
|
||||||
|
|
||||||
result match {
|
result match {
|
||||||
case dmc: DaemonMsgCreate ⇒
|
case dmc: DaemonMsgCreate ⇒
|
||||||
dmc.props.args should ===(Seq("a string": Any))
|
dmc.props.args should ===(Seq("a string": Any))
|
||||||
|
}
|
||||||
|
} finally {
|
||||||
|
TestKit.shutdownActorSystem(system)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,12 +3,15 @@
|
||||||
*/
|
*/
|
||||||
package akka.stream.impl
|
package akka.stream.impl
|
||||||
|
|
||||||
import org.reactivestreams.{ Subscriber, Publisher, Subscription }
|
import akka.annotation.InternalApi
|
||||||
|
import org.reactivestreams.{ Publisher, Subscriber, Subscription }
|
||||||
|
|
||||||
import scala.concurrent.{ ExecutionContext, Promise }
|
import scala.concurrent.{ ExecutionContext, Promise }
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* INTERNAL API
|
* INTERNAL API
|
||||||
*/
|
*/
|
||||||
|
@InternalApi
|
||||||
private[akka] case object EmptyPublisher extends Publisher[Nothing] {
|
private[akka] case object EmptyPublisher extends Publisher[Nothing] {
|
||||||
import ReactiveStreamsCompliance._
|
import ReactiveStreamsCompliance._
|
||||||
override def subscribe(subscriber: Subscriber[_ >: Nothing]): Unit =
|
override def subscribe(subscriber: Subscriber[_ >: Nothing]): Unit =
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,8 @@ import scala.concurrent.{ Future, Promise }
|
||||||
import akka.Done
|
import akka.Done
|
||||||
import java.util.concurrent.CompletionStage
|
import java.util.concurrent.CompletionStage
|
||||||
|
|
||||||
|
import akka.annotation.InternalApi
|
||||||
|
|
||||||
import scala.compat.java8.FutureConverters._
|
import scala.compat.java8.FutureConverters._
|
||||||
import scala.util.Try
|
import scala.util.Try
|
||||||
import scala.util.control.NonFatal
|
import scala.util.control.NonFatal
|
||||||
|
|
@ -396,3 +398,22 @@ final class LazySource[T, M](sourceFactory: () ⇒ Source[T, M]) extends GraphSt
|
||||||
override def toString = "LazySource"
|
override def toString = "LazySource"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** INTERNAL API */
|
||||||
|
@InternalApi
|
||||||
|
final object EmptySource extends GraphStage[SourceShape[Nothing]] {
|
||||||
|
val out = Outlet[Nothing]("EmptySource.out")
|
||||||
|
override val shape = SourceShape(out)
|
||||||
|
|
||||||
|
override protected def initialAttributes = DefaultAttributes.lazySource
|
||||||
|
|
||||||
|
override def createLogic(inheritedAttributes: Attributes): GraphStageLogic =
|
||||||
|
new GraphStageLogic(shape) with OutHandler {
|
||||||
|
override def preStart(): Unit = completeStage()
|
||||||
|
override def onPull(): Unit = completeStage()
|
||||||
|
|
||||||
|
setHandler(out, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
override def toString = "EmptySource"
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -328,10 +328,8 @@ object Source {
|
||||||
*/
|
*/
|
||||||
def empty[T]: Source[T, NotUsed] = _empty
|
def empty[T]: Source[T, NotUsed] = _empty
|
||||||
private[this] val _empty: Source[Nothing, NotUsed] =
|
private[this] val _empty: Source[Nothing, NotUsed] =
|
||||||
fromGraph(new PublisherSource[Nothing](
|
Source.fromGraph(EmptySource)
|
||||||
EmptyPublisher,
|
|
||||||
DefaultAttributes.emptySource,
|
|
||||||
shape("EmptySource")))
|
|
||||||
/**
|
/**
|
||||||
* Create a `Source` which materializes a [[scala.concurrent.Promise]] which controls what element
|
* Create a `Source` which materializes a [[scala.concurrent.Promise]] which controls what element
|
||||||
* will be emitted by the Source.
|
* will be emitted by the Source.
|
||||||
|
|
|
||||||
|
|
@ -45,7 +45,9 @@ object AskPattern {
|
||||||
}
|
}
|
||||||
|
|
||||||
private class PromiseRef[U](target: ActorRef[_], untyped: InternalActorRef, timeout: Timeout) {
|
private class PromiseRef[U](target: ActorRef[_], untyped: InternalActorRef, timeout: Timeout) {
|
||||||
val (ref: ActorRef[U], future: Future[U], promiseRef: PromiseActorRef) =
|
|
||||||
|
// Note: _promiseRef mustn't have a type pattern, since it can be null
|
||||||
|
private[this] val (_ref: ActorRef[U], _future: Future[U], _promiseRef) =
|
||||||
if (untyped.isTerminated)
|
if (untyped.isTerminated)
|
||||||
(
|
(
|
||||||
adapter.ActorRefAdapter[U](untyped.provider.deadLetters),
|
adapter.ActorRefAdapter[U](untyped.provider.deadLetters),
|
||||||
|
|
@ -59,6 +61,10 @@ object AskPattern {
|
||||||
val b = adapter.ActorRefAdapter[U](a)
|
val b = adapter.ActorRefAdapter[U](a)
|
||||||
(b, a.result.future.asInstanceOf[Future[U]], a)
|
(b, a.result.future.asInstanceOf[Future[U]], a)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val ref: ActorRef[U] = _ref
|
||||||
|
val future: Future[U] = _future
|
||||||
|
val promiseRef: PromiseActorRef = _promiseRef
|
||||||
}
|
}
|
||||||
|
|
||||||
private def askUntyped[T, U](target: ActorRef[T], untyped: InternalActorRef, timeout: Timeout, f: ActorRef[U] ⇒ T): Future[U] = {
|
private def askUntyped[T, U](target: ActorRef[T], untyped: InternalActorRef, timeout: Timeout, f: ActorRef[U] ⇒ T): Future[U] = {
|
||||||
|
|
|
||||||
82
akka-typed/src/test/scala/akka/typed/AskSpec.scala
Normal file
82
akka-typed/src/test/scala/akka/typed/AskSpec.scala
Normal file
|
|
@ -0,0 +1,82 @@
|
||||||
|
/**
|
||||||
|
* Copyright (C) 2017 Lightbend Inc. <http://www.lightbend.com>
|
||||||
|
*/
|
||||||
|
package akka.typed
|
||||||
|
|
||||||
|
import scala.concurrent.ExecutionContext
|
||||||
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
|
import org.scalatest.concurrent.ScalaFutures
|
||||||
|
|
||||||
|
import akka.util.Timeout
|
||||||
|
import akka.pattern.AskTimeoutException
|
||||||
|
|
||||||
|
import ScalaDSL._
|
||||||
|
import AskPattern._
|
||||||
|
|
||||||
|
object AskSpec {
|
||||||
|
|
||||||
|
sealed trait Msg
|
||||||
|
final case class Foo(s: String)(val replyTo: ActorRef[String]) extends Msg
|
||||||
|
final case class Stop(replyTo: ActorRef[Unit]) extends Msg
|
||||||
|
}
|
||||||
|
|
||||||
|
class AskSpec extends TypedSpec with ScalaFutures {
|
||||||
|
|
||||||
|
import AskSpec._
|
||||||
|
|
||||||
|
trait Common {
|
||||||
|
|
||||||
|
def system: ActorSystem[TypedSpec.Command]
|
||||||
|
|
||||||
|
implicit def executor: ExecutionContext =
|
||||||
|
system.executionContext
|
||||||
|
|
||||||
|
val behavior: Behavior[Msg] = Total[Msg] {
|
||||||
|
case foo @ Foo(_) ⇒
|
||||||
|
foo.replyTo ! "foo"
|
||||||
|
Same
|
||||||
|
case Stop(r) ⇒
|
||||||
|
r ! ()
|
||||||
|
Stopped
|
||||||
|
}
|
||||||
|
|
||||||
|
def `must fail the future if the actor is already terminated`(): Unit = {
|
||||||
|
val fut = for {
|
||||||
|
ref ← system ? TypedSpec.Create(behavior, "test1")
|
||||||
|
_ ← ref ? Stop
|
||||||
|
answer ← ref.?(Foo("bar"))(Timeout(1.second), implicitly)
|
||||||
|
} yield answer
|
||||||
|
(fut.recover { case _: AskTimeoutException ⇒ "" }).futureValue should ===("")
|
||||||
|
}
|
||||||
|
|
||||||
|
def `must succeed when the actor is alive`(): Unit = {
|
||||||
|
val fut = for {
|
||||||
|
ref ← system ? TypedSpec.Create(behavior, "test2")
|
||||||
|
answer ← ref ? Foo("bar")
|
||||||
|
} yield answer
|
||||||
|
fut.futureValue should ===("foo")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
object `Ask pattern (native)` extends Common with NativeSystem
|
||||||
|
|
||||||
|
object `Ask pattern (adapted)` extends Common with AdaptedSystem {
|
||||||
|
|
||||||
|
import AskSpec._
|
||||||
|
|
||||||
|
/** See issue #19947 (MatchError with adapted ActorRef) */
|
||||||
|
def `must fail the future if the actor doesn't exist`(): Unit = {
|
||||||
|
val noSuchActor: ActorRef[Msg] = system match {
|
||||||
|
case adaptedSys: adapter.ActorSystemAdapter[_] ⇒
|
||||||
|
adapter.actorRefAdapter(adaptedSys.untyped.provider.resolveActorRef("/foo/bar"))
|
||||||
|
case _ ⇒
|
||||||
|
fail("this test must only run in an adapted actor system")
|
||||||
|
}
|
||||||
|
val fut = for {
|
||||||
|
answer ← noSuchActor.?(Foo("bar"))(Timeout(1.second), implicitly)
|
||||||
|
} yield answer
|
||||||
|
(fut.recover { case _: AskTimeoutException ⇒ "" }).futureValue should ===("")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -17,7 +17,7 @@ object Dependencies {
|
||||||
val sslConfigVersion = "0.2.1"
|
val sslConfigVersion = "0.2.1"
|
||||||
val slf4jVersion = "1.7.23"
|
val slf4jVersion = "1.7.23"
|
||||||
val scalaXmlVersion = "1.0.6"
|
val scalaXmlVersion = "1.0.6"
|
||||||
val aeronVersion = "1.2.0"
|
val aeronVersion = "1.2.3"
|
||||||
|
|
||||||
val Versions = Seq(
|
val Versions = Seq(
|
||||||
crossScalaVersions := Seq("2.11.8", "2.12.1"),
|
crossScalaVersions := Seq("2.11.8", "2.12.1"),
|
||||||
|
|
|
||||||
|
|
@ -1 +1 @@
|
||||||
sbt.version=0.13.11
|
sbt.version=0.13.13
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue