Skip to content

Instantly share code, notes, and snippets.

@tompave
Created November 10, 2018 18:43
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save tompave/24c97237d5fd4049e245038ac6bfcf37 to your computer and use it in GitHub Desktop.
Save tompave/24c97237d5fd4049e245038ac6bfcf37 to your computer and use it in GitHub Desktop.
Actors and Messages in Ruby
require "colorize"
REGISTRY = {}
DEBUG = false
SLEEP = 0.5
def register(id)
mailbox = Queue.new
Thread.current[:process_id] = id
REGISTRY[id] = mailbox
[id, mailbox]
end
def mailbox(id)
mailbox = REGISTRY[id]
unless mailbox
raise "Error getting mailbox: unrecognized id #{id}"
end
mailbox
end
def new_id
@current_id ||= 0
@current_id += 1
end
def log(str)
return nil unless DEBUG
puts str
end
def current_id
Thread.current[:process_id]
end
def msg_send(to:, from:, msg:)
puts "sending <#{msg}> to #{to}, from #{from}".magenta
mailbox(to) << { from: from, body: msg }
true
end
def cast(to:, from:, msg:)
msg_send(to: to, from: from, msg: msg)
end
def call(to:, from:, msg:)
msg_send(to: to, from: from, msg: msg)
receive(block: true)
end
def receive(block: nil)
if block.nil?
non_block = (current_id == :main)
else
non_block = !block
end
mailbox(current_id).pop(non_block)
rescue ThreadError
nil
end
def spawn(&block)
id = new_id
Thread.new do
_id, mailbox = register(id)
loop do
log "-- id: #{id}, pending messages: #{mailbox.length}"
message = receive
log "-- id: #{id} received message: #{message}"
reply_to = message[:from]
body = message[:body]
begin
sleep SLEEP
result = block.call(body, id, reply_to)
if result != :noreply
msg_send(to: reply_to, from: id, msg: result)
end
rescue => e
msg_send(to: reply_to, from: id, msg: e)
end
end
end
id
end
@aa = spawn do |msg|
msg.upcase + "?"
end
@bb = spawn do |msg|
msg.reverse
end
@cc = spawn do |msg, own_id, from|
puts "received msg: #{msg} from: #{from}".yellow
if msg == "start"
msg_send(to: @aa, from: own_id, msg: "tommaso")
msg_send(to: @bb, from: own_id, msg: "tommaso")
end
:noreply
end
@ping = spawn do |msg, own_id, from|
puts "I'm PING, I've received #{msg}."
target = (msg.is_a?(Hash) && msg[:reply_to]) || from
msg_send to: target, from: own_id, msg: "PING"
:noreply
end
@pong = spawn do |msg, own_id, from|
puts "I'm PONG, I've received #{msg}."
target = (msg.is_a?(Hash) && msg[:reply_to]) || from
msg_send to: target, from: own_id, msg: "PONG"
:noreply
end
# -------------------------
register(:main)
def start
msg_send to: @cc, from: :main, msg: "start"
end
# start
# 10.times { |i| msg_send to: @aa, from: :main, msg: "ciao#{i}" }
# msg_send to: @ping, from: :main, msg: { reply_to: @pong }
# cast to: @bb, from: :main, msg: "tommaso"
# call to: @bb, from: :main, msg: "tommaso"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment