ActorSystem().ask doesn't receive custom message class response #6

Closed
fprimex opened this Issue Mar 18, 2016 · 2 comments

Comments

Projects
None yet
2 participants
@fprimex

fprimex commented Mar 18, 2016

When setting up an ActorSystem to perform an ask followed by a shutdown, the response to the ask is never received if the message sent is a custom message class.

I am using Thespian 2.5.7 as reported and installed by pip, on Python 3.5.1 as shipped in the Anaconda Python Distribution on Ubuntu 15.10 (Wily).

Please refer to the following testcase:

from thespian.actors import ActorSystem, ActorSystemMessage, \
    ActorTypeDispatcher


# Tried this too, just to make sure it wasn't the inheritance
#class TestMessage(object):
#    pass


class TestMessage(ActorSystemMessage):
    pass


class TestActor(ActorTypeDispatcher):
    def receiveMsg_TestMessage(self, msg, sender):
        # Does not result in ActorSystem('multiprocQueueBase') shut down
        # Does not result in ActorSystem('multiprocTCPBase') shut down
        # Does not result in ActorSystem('multiprocUDPBase') shut down
        self.send(sender, msg)

        # Neither does this
        #self.send(sender, TestMessage())

        # This *does* cause the system to shut down.
        # All ActorSystems work as expected, and print <class 'str'>
        #self.send(sender, 'done')


if __name__ == '__main__':
    #ActorSystem('simpleSystemBase')
    #ActorSystem('multiprocQueueBase')
    ActorSystem('multiprocTCPBase')
    #ActorSystem('multiprocUDPBase')

    addr = ActorSystem().createActor(TestActor)

    # multiprocQueueBase never receives response
    # multiprocTCPBase never receives response
    # multiprocUDPBase never receives response
    response = ActorSystem().ask(addr, TestMessage())

    # simpleSystemBase prints:
    # <class 'NoneType'>
    print(type(response))

    ActorSystem().shutdown()
@kwquick

This comment has been minimized.

Show comment
Hide comment
@kwquick

kwquick Mar 18, 2016

Contributor

Thank you for the concise and well-documented example and environment descriptions.

This is actually proper behavior for the current implementation, although a bit unexpected as you noted.

Thespian has various internal messages it uses to provide functionality and manage the ActorSystem. Most of these messages are intended to remain completely internal to Thespian, although some are sent to Actors or the external system (these are documented in http://thespianpy.com/using.html#outline-container-sec-7). All the messages documented in that location can be delivered to an Actor, but only a small subset of those can be delivered to the external system (specifically: Thespian_SystemStatus, Thespian_ActorStatus, and PoisonMessage). I have updated clarifications to the documentation in this regard (96c0fb5 and 5b214fd).

The other functionality you encountered is that the ask() will wait forever by default. There is an optional third argument that specifies a timeout, after which it will return None to indicate a timeout.

Thus, the overall sequence of events in your test above is:

  1. create actor system
  2. create actor
  3. deliver message to actor
  4. actor sends response
  5. ask() detects that response is a subclass of ActorSystemMessage but that it is not a PoisonMessage or one of the status messages so it is discarded
  6. the ask() has no timeout, so it waits indefinitely, thus the apparent lack of shutdown.

Perhaps confusingly, the simpleSystemBase has slightly different behavior than the other system bases. Because it is implemented as sequential calls entirely within the context of the current process, it will return from any ask() or tell() operation when there are no more messages to be sent (the alternative would be to sleep forever, which is less useful). This difference in behavior (which is rather opaquely described in http://thespianpy.com/using.html#sec-8-2) led to the confusion over the behavior of the other system bases.

In the commit I highlighted above, I also added a set of tests to validate this overall behavior. The one difference from your description above is that the version of TestMessage that subclasses object instead of ActorSystemMessage seemed to work fine for me with all bases, which is consistent with the functionality I've described here; I suspect your initial testing had some other issue that masked the functionality you expected when you used the object-derived TestMessage.

I hope this helps, and that the documentation clarifications are helpful. Please let me know if you have any suggestions for improvements in any of these areas.

Thank you,
Kevin

Contributor

kwquick commented Mar 18, 2016

Thank you for the concise and well-documented example and environment descriptions.

This is actually proper behavior for the current implementation, although a bit unexpected as you noted.

Thespian has various internal messages it uses to provide functionality and manage the ActorSystem. Most of these messages are intended to remain completely internal to Thespian, although some are sent to Actors or the external system (these are documented in http://thespianpy.com/using.html#outline-container-sec-7). All the messages documented in that location can be delivered to an Actor, but only a small subset of those can be delivered to the external system (specifically: Thespian_SystemStatus, Thespian_ActorStatus, and PoisonMessage). I have updated clarifications to the documentation in this regard (96c0fb5 and 5b214fd).

The other functionality you encountered is that the ask() will wait forever by default. There is an optional third argument that specifies a timeout, after which it will return None to indicate a timeout.

Thus, the overall sequence of events in your test above is:

  1. create actor system
  2. create actor
  3. deliver message to actor
  4. actor sends response
  5. ask() detects that response is a subclass of ActorSystemMessage but that it is not a PoisonMessage or one of the status messages so it is discarded
  6. the ask() has no timeout, so it waits indefinitely, thus the apparent lack of shutdown.

Perhaps confusingly, the simpleSystemBase has slightly different behavior than the other system bases. Because it is implemented as sequential calls entirely within the context of the current process, it will return from any ask() or tell() operation when there are no more messages to be sent (the alternative would be to sleep forever, which is less useful). This difference in behavior (which is rather opaquely described in http://thespianpy.com/using.html#sec-8-2) led to the confusion over the behavior of the other system bases.

In the commit I highlighted above, I also added a set of tests to validate this overall behavior. The one difference from your description above is that the version of TestMessage that subclasses object instead of ActorSystemMessage seemed to work fine for me with all bases, which is consistent with the functionality I've described here; I suspect your initial testing had some other issue that masked the functionality you expected when you used the object-derived TestMessage.

I hope this helps, and that the documentation clarifications are helpful. Please let me know if you have any suggestions for improvements in any of these areas.

Thank you,
Kevin

@fprimex

This comment has been minimized.

Show comment
Hide comment
@fprimex

fprimex Mar 18, 2016

I must have made a mistake when working through all of the combinations of possibilities. I've just retested with TestMessage(object) instead of TestMessage(ActorSystemMessage) and indeed it does work as expected for my environment. Must have forgotten to actually write the file for the object test run.

I will avoid subclassing ActorSystemMessage and all should be well. Thanks for the in-depth explanation!

fprimex commented Mar 18, 2016

I must have made a mistake when working through all of the combinations of possibilities. I've just retested with TestMessage(object) instead of TestMessage(ActorSystemMessage) and indeed it does work as expected for my environment. Must have forgotten to actually write the file for the object test run.

I will avoid subclassing ActorSystemMessage and all should be well. Thanks for the in-depth explanation!

@fprimex fprimex closed this Mar 18, 2016

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment