Playing with making an Actor-like distributed system in REBOL
April 12th, 2009For 3 weeks I was continuously working on the stuff that needs to be worked on. It was interesting, but yesterday I needed a small break. I decided to take some time for playing/exploring.
I wanted to see how something similar to an actor based system with message passing can be made at all. I was thinking of trying to make one in REBOL ever since I watched an interesting video named “Concurrency and Distributed Computing with Python Today” by Jesse Noller from this year’s PyCon.
Don’t compare it too much to Erlang’s actors. I tried to name them agents to avoid the comparison but then I couldn’t find the good name for word act so I renamed them back.
So what is my goal for now: Create a minimal system that runs some separated blocks of code that communicate to each other via uni-directional messages.
Inside one process, with groups
At first I created this system within one process, the code was really simple so I added some group functionality. An actor could say, send message to random actor of this kind. For example: send “parse-page X” to one of the actors of the “webpage-parsers” group. I created 2 types of actors, one wakes up and acts only when it has a message waiting in his mailbox, the other, the timer-actor, wakes up on specified intervals.
Here is the code of the test I used. It creates 2 timer actors dogs-owner, and dogs-trainer that send messages to the 2 actors of “dogs” group.
dogs-owner: make timer-actor [ timer-act: [ send-msg/group 'hey "dogs" print "dog owner->hey!"] interval: 0:00:3 ] dogs-trainer: make timer-actor [ timer-act: [ send-msg/group 'stick "dogs" print "dog trainer->stick!"] interval: 0:00:8 ] dog-actor: make actor [ act-hey: copy [] act-stick: copy [] act: [ switch take mbox [ hey [ do act-hey ] stick [ do act-stick ] ] ] ] big-dog: make dog-actor [ act-hey: [ print "big dog<-wof" ] act-stick: [ print "big dog<-meh sleeping.." ] ] small-dog: make dog-actor [ act-hey: [ print "small dog<-bewsk bewsk" ] act-stick: [ print "small dog<-run & jump.." ] ] add-actor/group small-dog "dogs" add-actor/group big-dog "dogs" add-actor dogs-owner add-actor dogs-trainer start-actors
We get an output that looks something like this:
dog owner->hey!
big dog<-wof
dog owner->hey!
small dog<-bewsk bewsk
dog trainer->stick!
big dog<-meh sleeping..
dog owner->hey!
mutt dog<-weff
dog owner->hey!
...
Distributed actors via TCP
OK, so now the in-process actors work and we can upgrade message passing so that it will also work over TCP connection. With this, actors will be able to send messages to actors that live inside different process on the same or another computer. I decided to remove the groups functionality because it was premature optimization feature. To test this we have two separate processes and so two scripts.
Cats process, runs one actor (cat-boss) that acts on 2 different messages.
print "Actor-net example (cats)"
do %actor-net-lib_v1.r
*my-port*: 5602
cat-boss: make actor [
act: [ msg: take mbox
switch first msg [
still-seeking [ print "cat boss: our cat agent is still seeking" ]
found-fish [ print "cat boss: yeey, we found a fish!!" ]
]
]
]
add-local-actor cat-boss
start-remote-listener
start-actors
Dogs process, consists of 3 actors. The cat-agent actor sends messages to cat-boss in the other process. His send message code is no different than when sending it in the same process, only the actor address is different.
print "Actor-net example (dogs)"
do %actor-net-lib_v1.r
*my-port*: 5601
dog-boss: make timer-actor [
timer-act: [
send-msg local-dog-addr [ watch-for-cats ]
print "dog boss -> local dog: 'Watch for cats!'"
]
interval: 0:00:7
]
local-dog: make actor [
act: [ msg: take mbox
switch first msg [
watch-for-cats [ print "local dog: I am! wof!" ]
]
]
]
cat-agent: make timer-actor [
timer-act: [
send-msg cat-boss-addr either equal? 1 random 3 [
print "cat agent -> remote boss: 'found a fish'"
[ found-fish ]
] [
print "cat agent -> remote boss: 'still seeking'"
[ still-seeking ]
]
]
interval: 0:00:6
]
cat-boss-addr: make actor-addr! [ port: 5602 id: 1 ]
local-dog-addr: make actor-addr! [ port: 5601 id: 2 ]
add-local-actor dog-boss
add-local-actor local-dog
add-local-actor cat-agent
start-remote-listener
start-actors
The code to make this work is really simple and only a little above 100loc, so you should have no big problems understanding and tweaking it. It uses async. tcp networking via async-protocol.r library . When we run both script we get something like this:
cats script:
Actor-net example (cats)
cat boss: our cat agent is still seeking
cat boss: yeey, we found a fish!!
cat boss: our cat agent is still seeking
cat boss: our cat agent is still seeking
...
dogs script:
Actor-net example (dogs)
cat agent -> remote boss: 'still seeking'
dog boss -> local dog: 'Watch for cats!'
local dog: I am! wof!
cat agent -> remote boss: 'found a fish'
dog boss -> local dog: 'Watch for cats!'
local dog: I am! wof!
cat agent -> remote boss: 'still seeking'
dog boss -> local dog: 'Watch for cats!'
local dog: I am! wof!
cat agent -> remote boss: 'still seeking'
dog boss -> local dog: 'Watch for cats!'
local dog: I am! wof!
...
What to improve?
Hm.. what not
. No really, this is just some playing around. There is tons of things that I even don’t know how I want to look or function. Few that pop in my head right now:
- elegant process addressing, passing process addresses around, the sender address?
- more elegant switching on received message, Erlang has native pattern matching for example
- rethink how actors are built (they are rebol objects now)
- rethink how state in actors is handled, for example an actor might have a persistent connection to database
- … tons more …
My goal is not to mimic Erlang actors exactly, but to see if I can build a nice and practical system for distributed systems with this.
I have made up from my head up to now, and I never want to over think stuff in advance, because concrete situations later show the real answers. I will try to build a real app for my real needs and I think this will give me many answers to open questions. I will soon need to make a network of bots for Site Assistant that are just “ocasionally online” and that provide some service to the main app server. I think this should be a nice little challenge to push this forward.
Related articles by Zemanta
- Erlang and Distributed Key Value Stores (torrez.us)
- Erlang Musings (mykakotopia.blogspot.com)
- Python, Erlang, Hadoop, Git and Sparklines (davidcancel.com)

![Reblog this post [with Zemanta]](http://img.zemanta.com/reblog_e.png?x-id=ec3092b5-2449-461b-ab03-4d4c143d4b31)
October 19th, 2009 at 7:08 am
[...] sitting on my disc for weeks, but didn’t find time to post it. There are few advances from #1, but it’s still focused on just playing, trying out stuff. I am also posting this because [...]
October 19th, 2009 at 7:12 am
[...] library source code. See the previous two posts to get more info about what is what and why: #1 , #2 [...]