Project

actory

0.0
No commit activity in last 3 years
No release in over 3 years
Actor model like, concurrent and distributed framework for Ruby.
2005
2006
2007
2008
2009
2010
2011
2012
2013
2014
2015
2016
2017
2018
2019
2020
2021
2022
2023
2024
 Dependencies

Development

Runtime

 Project Readme

actory

Actor model like, concurrent and distributed framework for Ruby.

Installation

gem install actory

Setup

path_to_actory="/PATH/TO/GEMS/actory-0.0.1"
export PATH=$PATH:$path_to_actory/bin
  • /PATH/TO/GEMS above means the path to the directory of gem files. e.g. $HOME/.rvm/gems/ruby-2.0.0-p247@global/gems

System-wide setup with the root permission

sudo mkdir -p /etc/actory
sudo cp -p $path_to_actory/config/receiver.yml.example /etc/actory
sudo cp -p $path_to_actory/config/sender.yml.example /etc/actory

System-wide setup under the RubyGems

cd $path_to_actory/config
cp receiver.yml.example receiver.yml
cp sender.yml.example sender.yml
sed -i '' "s/\/etc\/actory/\.\.\/\.\.\/\.\.\/config/g" global.yml

Setup inside of each indivisual project

echo "gem actory" >> Gemfile
bundle install --path vendor/bundle
cp ./vendor/bundle
path_to_actory="vendor/bundle/ruby/2.0.0/gems/actory-0.0.1"
cp $path_to_actory/config/receiver.yml.example $path_to_actory/config/receiver.yml
cp $path_to_actory/config/sender.yml.example $path_to_actory/config/sender.yml
sed -i '' "s/\/etc\/actory/\.\.\/\.\.\/\.\.\/config/g" $path_to_actory/config/global.yml

Architecture

  • Actor model like message passing API
  • Dynamically loaded plugins
  • High concurrency
  • Low overheads

System-wide

Sending a message to each receiver to make it deal with the message.

  +--------+
  |user app|
  +--------+
    | message(method, [args]) # [args].size # => i
    v
  +------------------+
  |Sender::Dispatcher|
  +------------------+
    |                                                           execute
    |   +----------------+ msgpack-rpc +----------------------+ method(arg[0]) +----------------+
    +-->|sub-process #1/n|------------>|Receiver::EventHandler|--------------->|Receiver::Plugin|
    |   +----------------+             +----------------------+ execute        +----------------+
    |   +----------------+             +----------------------+ method(arg[1]) +----------------+
    +-->|sub-process #2/n|------------>|Receiver::EventHandler|--------------->|Receiver::Plugin|
    |   +----------------+             +----------------------+       :        +----------------+
    |         :                                 :               execute                :
    |   +----------------+             +----------------------+ method(arg[i]) +----------------+
    `-->|sub-process #n/n|------------>|Receiver::EventHandler|--------------->|Receiver::Plugin|
        +----------------+             +----------------------+                +----------------+

Receiving each returned value at once.

  +--------+
  |user app|
  +--------+
    ^ an array value in [{"host:port" => [return_value(s), ...]}, ... ]
    |
  +------------------+
  |Sender::Dispatcher|
  +------------------+
    ^                                                              return
    |   +----------------+ msgpack-rpc +----------------------+   value(s)   +----------------+
    +---|sub-process #1/n|<------------|Receiver::EventHandler|<-------------|Receiver::Plugin|
    |   +----------------+             +----------------------+              +----------------+
    |   +----------------+             +----------------------+              +----------------+
    +---|sub-process #2/n|<------------|Receiver::EventHandler|<-------------|Receiver::Plugin|
    |   +----------------+             +----------------------+              +----------------+
    |         :                                 :                                     :
    |   +----------------+             +----------------------+              +----------------+
    `---|sub-process #n/n|<------------|Receiver::EventHandler|<-------------|Receiver::Plugin|
        +----------------+             +----------------------+              +----------------+

Jobs can be assigned flexibly.

  +--------+
  |user app|
  +--------+
    | message(method, [args]) # [args].size # => i; i > n # => true
    v
  +------------------+
  |Sender::Dispatcher|
  +------------------+
    |                                                           execute
    |   +----------------+ msgpack-rpc +----------------------+ method(arg[0])   +----------------+
    +-->|sub-process #1/n|------------>|Receiver::EventHandler|----------------->|Receiver::Plugin|
    |   |                |             +----------------------+ execute          +----------------+
    |   |                |             +----------------------+ method(arg[i])   +----------------+
    +-->|                |------------>|Receiver::EventHandler|----------------->|Receiver::Plugin|
    |   +----------------+             +----------------------+ execute          +----------------+
    |   +----------------+             +----------------------+ method(arg[1])   +----------------+
    +-->|sub-process #2/n|------------>|Receiver::EventHandler|----------------->|Receiver::Plugin|
    |   +----------------+             +----------------------+       :          +----------------+
    |         :                                 :               execute                   :
    |   +----------------+             +----------------------+ method(arg[i-1]) +----------------+
    `-->|sub-process #n/n|------------>|Receiver::EventHandler|----------------->|Receiver::Plugin|
        +----------------+             +----------------------+                  +----------------+
  +--------+
  |user app|
  +--------+
    | message(method, [args]) # [args].size # => i; n > i # => true
    v
  +------------------+
  |Sender::Dispatcher|
  +------------------+
    |                                                           execute
    |   +----------------+ msgpack-rpc +----------------------+ method(arg[0]) +----------------+
    +-->|sub-process #1/n|------------>|Receiver::EventHandler|--------------->|Receiver::Plugin|
    |   +----------------+             +----------------------+ execute        +----------------+
    |   +----------------+             +----------------------+ method(arg[i]) +----------------+
    `-->|sub-process #2/n|------------>|Receiver::EventHandler|--------------->|Receiver::Plugin|
        +----------------+             +----------------------+                +----------------+
              :                                 :                                       :
        +----------------+             +----------------------+                +----------------+
        |sub-process #n/n|             |Receiver::EventHandler|                |Receiver::Plugin|
        +----------------+             +----------------------+                +----------------+
  +--------+
  |user app|
  +--------+
    | message(method, [args]) # [args].size # => 1
    v
  +------------------+
  |Sender::Dispatcher|
  +------------------+
    |                                                           execute
    |   +----------------+ msgpack-rpc +----------------------+ method(arg[0]) +----------------+
    `-->|sub-process #1/n|------------>|Receiver::EventHandler|--------------->|Receiver::Plugin|
        +----------------+             +----------------------+                +----------------+
        +----------------+             +----------------------+                +----------------+
        |sub-process #2/n|             |Receiver::EventHandler|                |Receiver::Plugin|
        +----------------+             +----------------------+                +----------------+
              :                                 :                                       :
        +----------------+             +----------------------+                +----------------+
        |sub-process #n/n|             |Receiver::EventHandler|                |Receiver::Plugin|
        +----------------+             +----------------------+                +----------------+

Receiver

  +--------------------------------------------------------------------------+
  | a receiver                                                               |
  |                                                                          |
  | +--------+                                                               |
  | | Worker |                                                               |
  | +--------+                                                               |
  |   |                                 +-------------+                      |
  |   | spawn when started              |     CPU     |                      |
  |   |   +-------------------------+   | +---------+ |  +-----------------+ |
  |   +-->|Msgpack::RPC::Server #1/n|-->| |core #1/n|--->|EventHandler #1/n| |
  |   |   +-------------------------+   | +---------+ |  +-----------------+ |
  |   |   +-------------------------+   | +---------+ |  +-----------------+ |
  |   +-->|Msgpack::RPC::Server #2/n|-->| |core #2/n|--->|EventHandler #2/n| |
  |   |   +-------------------------+   | +---------+ |  +-----------------+ |
  |   |              :                  |      :      |          :           |
  |   |   +-------------------------+   | +---------+ |  +-----------------+ |
  |   `-->|Magpack::RPC::Server #n/n|-->| |core #n/n|--->|EventHandler #n/n| |
  |       +-------------------------+   | +---------+ |  +-----------------+ |
  |                                     |             |                      |
  |                                     +-------------+                      |
  |                                                                          |
  +--------------------------------------------------------------------------+

Sender

  +-----------------------------------------------------+  +-----------------------------+
  | a sender                                            |  | receiver(s)                 |
  |                                                     |  |                             |
  | +------------+                                      |  |                             |
  | | Dispatcher |                                      |  |                             |
  | +------------+                                      |  |                             |
  |   |                                 +-------------+ |  |                             |
  |   | spawn when instantized          |     CPU     | |  |                             |
  |   |   +-------------------------+   | +---------+ | |  | +-------------------------+ |
  |   +-->|Msgpack::RPC::Client #1/n|-->| |core #1/n|------->|Msgpack::RPC::Server #1/m| |
  |   |   +-------------------------+   | +---------+ | |  | +-------------------------+ |
  |   |   +-------------------------+   | +---------+ | |  | +-------------------------+ |
  |   +-->|Msgpack::RPC::Client #2/n|-->| |core #2/n|------->|Msgpack::RPC::Server #2/m| |
  |   |   +-------------------------+   | +---------+ | |  | +-------------------------+ |
  |   |              :                  |      :      | |  |            :                |
  |   |   +-------------------------+   | +---------+ | |  | +-------------------------+ |
  |   `-->|Magpack::RPC::Client #n/n|-->| |core #n/n|------->|Msgpack::RPC::Server #m/m| |
  |       +-------------------------+   | +---------+ | |  | +-------------------------+ |
  |                                     |             | |  |                             |
  |                                     +-------------+ |  |                             |
  |                                                     |  |                             |
  +-----------------------------------------------------+  +-----------------------------+

Configuration

config/receiver.yml

  • protocol
    • "tcp" or "udp"
  • address
    • Binding IP Address.
  • port
    • Port number to begin increment.
  • shared_key
    • A pre-shared key string to establish connections with a sender.
  • log
    • type
      • The type of the log. "stdout", "file" or "both".
    • level
      • A log level. "fatal", "error", "warn", "info" or "debug".
    • target
      • The log file path, used when the "type" is specified as "file" or "both".

config/sender.yml

  • actors
    • A list of actors. The format is "host_name_or_ip_address:port".
  • policy
    • The policy to select actors and assign a message to them. "even", "random" or "safe-random".
  • timeout
    • Connection timeout value for msgpack-rpc.
  • get_interval
    • An interval to retry the get method for msgpack-rpc.
  • auth
    • shared_key
      • A pre-shared key string to establish connections with each receiver.
    • timeout
      • Authentication timeout with each receiver.
  • show_progress
    • If it is true, the sender shows you a progress bar.
  • reload_receiver_plugins
    • If it is true, the sender force each receiver reload plugins even in running.
  • log
    • type
      • The type of the log. "stdout", "file" or "both".
    • level
      • A log level. "fatal", "error", "warn", "info" or "debug".
    • target
      • The log file path, used when the "type" is specified as "file" or "both".

Usage

Receiver

Foreground

actory-receiver

Background

actory-receiver -d

Sender

require 'actory'
dispacher = Actory::Sender::Dispatcher.new
res = dispatcher.message(METHOD, ARGS)

You can specify an actor or actors with an argument with actors keyword.

require 'actory'
dispacher = Actory::Sender::Dispatcher.new(actors: ["localhost:18800"])
res = dispatcher.message(METHOD, ARGS)
require 'actory'
actors = ["192.168.1.1:18800", "192.168.1.2:18800", "192.168.1.3:18800"]
dispacher = Actory::Sender::Dispatcher.new(actors: actors)
res = dispatcher.message(METHOD, ARGS)

Plugin

You can create your own plugin(s) to be executed by the receiver.

module Actory
module Receiver

class Plugin < Base

  def hello(arg)
    return "Hello #{arg}."
  rescue => e
    msg = Actory::Errors::Generator.new.json(level: "ERROR", message: e.message, backtrace: $@)
    raise StandardError, msg
  end

end

end
end

If you have created a plugin, put it just under the lib/actory/receiver/plugin directory. Then it will be automatically loaded even in the receiver running.

And then, you can call the method from a sender like following:

require 'actory'
dispacher = Actory::Sender::Dispatcher.new
res = dispatcher.message("hello", ["world", "actory"])

The response in an array will be like following:

p res
[{"127.0.0.1:18800"=>["Hello world."]}, {"192.168.1.1:18800"=>["Hello actory."]}]

License

Apache License, Version 2.0