Skip to content

Commit

Permalink
Clarify ActorSystemMessage representation and delivery and add unit t…
Browse files Browse the repository at this point in the history
…ests.
  • Loading branch information
kwquick committed Mar 18, 2016
1 parent f8a93ba commit 96c0fb5
Show file tree
Hide file tree
Showing 2 changed files with 89 additions and 9 deletions.
28 changes: 19 additions & 9 deletions doc/using.org
Expand Up @@ -407,7 +407,11 @@ described in [[*Dead Letter Handling][Dead Letter Handling]].

* Guidelines for Actors and their messages

- All ActorSystem messages are derived from ActorSystemMessage.
- All ActorSystem internal messages are derived from
ActorSystemMessage. Messages sent by Actors should not subclass
ActorSystemMessage, but Actors may differentiate their messages
from Thespian messages by ~isinstance()~ testing against the
ActorSystemMessage.

- Actors should discard messages they do not recognize.

Expand Down Expand Up @@ -2011,17 +2015,23 @@ class SimpleSourceAuthority(ActorTypeDispatcher):
* ActorSystem Messages

The following Messages can be delivered to Actors by the ActorSystem
as a result of events within the ActorSystem itself.
as a result of events within the ActorSystem itself. All of these
messages inherit from the ActorSystemMessage.

In addition, the PoisonMessage may be delivered to external code (as
a response to an ~ActorSystem().tell()~ or ~ActorSystem().ask()~
call). All other ActorSystemMessage instances are filtered and not
returned to an ~ask()~ or ~tell()~ call.

** PoisonMessage

The ~PoisonMessage~ object is delivered to an Actor when a send
attempt by that Actor has caused the target Actor to fail. The
~PoisonMessage~ is a wrapper around the original message that
caused the failure. The originating Actor receives this poison
message indication to allow it to perform any desired cleanup or
alternative work based on the target Actor failure (see
[[*PoisonMessage Returns][PoisonMessage Returns]]).
The ~PoisonMessage~ object is delivered to an Actor or to external
code when message sent to an Actor has caused the target Actor to
fail. The ~PoisonMessage~ is a wrapper around the original message
that caused the failure. The originating sender receives this
poison message indication to allow it to perform any desired
cleanup or alternative work based on the target Actor failure (see [[*PoisonMessage
Returns][PoisonMessage Returns]]).

*** Attributes

Expand Down
70 changes: 70 additions & 0 deletions thespian/test/testSystemMessages.py
@@ -0,0 +1,70 @@
import unittest
import logging
import time, datetime
import thespian.test.helpers
from thespian.actors import *
from thespian.test import ActorSystemTestCase


class EchoActor(Actor):
def receiveMessage(self, msg, sender):
logging.info('EchoActor got %s (%s) from %s', msg, type(msg), sender)
self.send(sender, msg)


class FakeSystemMessage(ActorSystemMessage):
pass


smallwait = datetime.timedelta(milliseconds=50)


class TestASimpleSystem(ActorSystemTestCase):
testbase='Simple'
scope='func'

def testCreateActorSystem(self):
pass

def testSimpleActor(self):
echo = ActorSystem().createActor(EchoActor)

def testSimpleMessageTell(self):
echo = ActorSystem().createActor(EchoActor)
ActorSystem().tell(echo, 'hello')
time.sleep(0.02) # allow tell to work before ActorSystem shutdown

def testSystemMessageTell(self):
echo = ActorSystem().createActor(EchoActor)
ActorSystem().tell(echo, FakeSystemMessage())
time.sleep(0.02) # allow tell to work before ActorSystem shutdown

def testSimpleMessageAsk(self):
echo = ActorSystem().createActor(EchoActor)
self.assertEqual(ActorSystem().ask(echo, 'hello', smallwait), 'hello')

def testSystemMessageAsk(self):
echo = ActorSystem().createActor(EchoActor)
# SystemMessages are explicitly filtered from being returned
# via Ask() or Tell(), with the exception of PoisonMessage.
self.assertIsNone(ActorSystem().ask(echo, FakeSystemMessage(), smallwait))


class TestMultiprocUDPSystem(TestASimpleSystem):
testbase='MultiprocUDP'
def setUp(self):
self.setSystemBase('multiprocUDPBase')
super(TestMultiprocUDPSystem, self).setUp()

class TestMultiprocTCPSystem(TestASimpleSystem):
testbase='MultiprocTCP'
def setUp(self):
self.setSystemBase('multiprocTCPBase')
super(TestMultiprocTCPSystem, self).setUp()

class TestMultiprocQueueSystem(TestASimpleSystem):
testbase='MultiprocQueue'
def setUp(self):
self.setSystemBase('multiprocQueueBase')
super(TestMultiprocQueueSystem, self).setUp()

0 comments on commit 96c0fb5

Please sign in to comment.