Passing Constructor arguments to an actor?

142 views
Skip to first unread message

andreas....@gmail.com

unread,
Apr 30, 2019, 2:03:33 AM4/30/19
to thespian.py
Hi,

I am quite new to actor systems, and struggle a bit with actor construction.

To parallely access an API by several actors, I need to set them up with different credentials to log in to the API. As the actors are killed and recreated on an Exception and also get delivered the Exception causing message again, it would be quiet handy to pass the actors some init values on the ActorSystem().create(ActorClass) call. 

In the thespian utilities class I found the method withPossibleInitArgs but it seems to be only for internal use to deal with capabilities and requirements.

My only solution I came up with to have an actor initialised befor it gets resent the Exception causing message again would be a something like this:


class UniqueAppInventoryManager(Actor):
def __init__(self):
self.request_count = 0
# on error, the Actor has been configured allready once before.
if self.shop_url and self.api_key and self.password:
shopify.ShopifyResource.set_site(self.shop_url)
shopify.ShopifyResource.set_user(self.api_key)
shopify.ShopifyResource.set_password(self.password)
super(Actor, self).__init__()

def receiveMessage(self, message, sender):
if isinstance(message, SetupMessage):
self.shop_url = message.shop_url
self.api_key = message.api_key
self.password = message.password
shopify.ShopifyResource.set_site(message.shop_url)
shopify.ShopifyResource.set_user(message.api_key)
shopify.ShopifyResource.set_password(message.password)
self.send(sender, 'Setup WorkerActor')

else:
# ...
# ... do your actual work ...
# ...

And send the actor a init message after first creation. 

Do you have an other solution I miss here?

Thanks for your support.
Andreas

Kevin Quick

unread,
Apr 30, 2019, 2:31:27 AM4/30/19
to andreas....@gmail.com, thespian.py
The general method you are using is the one I would recommend: using an initial setup message. It is not possible to pass arguments to the init because that init might be done in another process, so the arguments would essentially become a message to that process anyhow.

If the values seem to be available at init time it should be ok to use them, but I would not usually expect this to be the case.

There is a decorator that can help you write actors that need these types of initialization messages: see thespian/initmsgs.py for more details.

Two small notes about the code you posted:

1. I would recommend using the customary pattern of "def __init__(*args, **kw)" and then "super(...).__init__(*args, **kw)". There are currently no positional or keyword arguments for the base class, but using the pattern will future proof in the event that some are added in a subsequent release. (You should not need to worry about the __init__ if you use the decorator above)

2. It looks like the shopify.ShopifyResource is global. Be careful because if you call self.createActor it will sometimes create the new actor by cloning the current actor's process, which would cause the new actor process to inherit the credentials of the creating actor.

-Kevin

--
You received this message because you are subscribed to the Google Groups "thespian.py" group.
To unsubscribe from this group and stop receiving emails from it, send an email to thespianpy+...@googlegroups.com.
To post to this group, send email to thesp...@googlegroups.com.
To view this discussion on the web visit https://groups.google.com/d/msgid/thespianpy/2adb6056-7145-4dbc-a92f-e652c8e18f9b%40googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

BR

unread,
Apr 30, 2019, 7:53:15 AM4/30/19
to thespian.py
I you're open to unsolicited advice, I would recommend using the ActorTypeDispatcher as in the following example instead of just Actor for your base class. It allows you to define your messages as a class (for example) and then you will have a single method which will process only that message. I found it helps avoid the if/elif/else and isinstance cascades which could be hard to follow as your number of messages increase. The only "gotcha" that I've experienced thus far is that if you have a typo, then I'm not sure where the message goes, but it won't be processed by your actor. I have found it makes for tidier code. Also, just to clarify, the name of your message class would go after the underscore ( _ ). 

class Typer(ActorTypeDispatcher):

    def receiveMsg_str(self, message, sender):
        self.send(sender, "Got a string")

    def receiveMsg_int(self, message, sender):
        self.send(sender, "Got an int")


Kevin Quick

unread,
Apr 30, 2019, 8:22:14 AM4/30/19
to BR, thespian.py
If you have a typo it won't match, but you can add a method for handling unrecognized messages; logging those helps with debugging.  The documentation for the ActorTypeDispatcher describes this everyone in more detail.

--
You received this message because you are subscribed to the Google Groups "thespian.py" group.
To unsubscribe from this group and stop receiving emails from it, send an email to thespianpy+...@googlegroups.com.
To post to this group, send email to thesp...@googlegroups.com.

andreas....@gmail.com

unread,
Apr 30, 2019, 9:41:54 AM4/30/19
to thespian.py
H Keven, hi BR!

Thanks for your fast answers! I will add below:


Am Dienstag, 30. April 2019 08:31:27 UTC+2 schrieb Kevin Quick:
The general method you are using is the one I would recommend: using an initial setup message. It is not possible to pass arguments to the init because that init might be done in another process, so the arguments would essentially become a message to that process anyhow.

Makes sense. Slowly starts to get clear, what happens local or remote...
 
If the values seem to be available at init time it should be ok to use them, but I would not usually expect this to be the case.

I guess, only in the Exception case. Otherwise it could not work. Maybe it was just a bad idea on the end of a long day. :)
 
There is a decorator that can help you write actors that need these types of initialization messages: see thespian/initmsgs.py for more details.

I will dig into this, sounds interesting!
 
Two small notes about the code you posted:

1. I would recommend using the customary pattern of "def __init__(*args, **kw)" and then "super(...).__init__(*args, **kw)". There are currently no positional or keyword arguments for the base class, but using the pattern will future proof in the event that some are added in a subsequent release. (You should not need to worry about the __init__ if you use the decorator above)

I guess, this is general in Python development. There is a lot I still have room for improvement there :)

 
2. It looks like the shopify.ShopifyResource is global. Be careful because if you call self.createActor it will sometimes create the new actor by cloning the current actor's process, which would cause the new actor process to inherit the credentials of the creating actor.

Thanks for the warning! Never would have thought about that! 


Am Dienstag, 30. April 2019 13:53:15 UTC+2 schrieb BR:
I you're open to unsolicited advice, I would recommend using the ActorTypeDispatcher as in

Thanks for that input! I stumbled above it later in the documentation. Looks like a good way to set up things. Looks much clearer than if cascades. Logging unmatched is for sure important! This has been nice in Scala, with their pattern matching if I remember correct. Some years ago already... 


In general... As far as I remember, the general approach with actors had been to just kill an actor on failur and create a new one by the parent actor. Does sending the failed message once again not contradict this?

Kevin Quick

unread,
Apr 30, 2019, 7:02:30 PM4/30/19
to andreas....@gmail.com, thespian.py
A single resend of a failed message is intended as a convenience to accommodate a transient failure: in practice the resend is likely to fail as well and you will do recovery as expected.

As a general note, the "let it fail" conceptual approach grew out of the convenience provided by the actor model, but it is not stipulated by the model itself. Because actors are isolated and asynchronous, it's easy to let one fail because that does not disable other parts of the application, and the actor is responsible for it's own initialization, so there is not a lot of complication in surrounding elements needing to track the state of other things since this is managed internally.

-Kevin

--
You received this message because you are subscribed to the Google Groups "thespian.py" group.
To unsubscribe from this group and stop receiving emails from it, send an email to thespianpy+...@googlegroups.com.
To post to this group, send email to thesp...@googlegroups.com.

andreas....@gmail.com

unread,
May 1, 2019, 6:11:29 AM5/1/19
to thespian.py
I unserstand. Do you maybe have a recommendation for a good read about design principles/patters for actor based programming?

Kevin Quick

unread,
May 5, 2019, 7:58:52 PM5/5/19
to andreas....@gmail.com, thespian.py
No particular recommendation. The Wikipedia article is a good place to start with some references. Ghul Agha's dissertation and Carl Hewitt's writings are the most definitive ok the subject.

-Kevin

--
You received this message because you are subscribed to the Google Groups "thespian.py" group.
To unsubscribe from this group and stop receiving emails from it, send an email to thespianpy+...@googlegroups.com.
To post to this group, send email to thesp...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages