Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Actress merge #73

Merged
merged 30 commits into from
May 26, 2014
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
1bb6304
Raw port of Actress
pitr-ch May 12, 2014
e6d4001
Change Abstract actor class to a ActorContext module
pitr-ch May 12, 2014
6887f78
Remove Algebrick dependency
pitr-ch May 13, 2014
19466d1
when spawn returns children are set
pitr-ch May 13, 2014
39173fe
Reject all envelops sent to termiated actor before actor is GCed
pitr-ch May 13, 2014
ecd97ac
Remove dead code
pitr-ch May 13, 2014
82c1a7f
Remove dependency on Atomic
pitr-ch May 13, 2014
4b9bed5
Remove unused mutex
pitr-ch May 13, 2014
2b86bc2
Add Reference#ask!
pitr-ch May 16, 2014
c20520b
TODOs and comments update
pitr-ch May 16, 2014
f473249
Split files and add documentation
pitr-ch May 20, 2014
b399efe
Add Actress::AdHoc actor
pitr-ch May 20, 2014
0ec8e08
Configurable Core
pitr-ch May 21, 2014
363e7b8
configurable log level
pitr-ch May 22, 2014
55d2ab6
Terminate on error in message processing
pitr-ch May 22, 2014
1d20305
Add basic spec
pitr-ch May 22, 2014
67a0671
Replace Array of children with more effective Set
pitr-ch May 23, 2014
314a26d
Make name and executor publicly accessible
pitr-ch May 23, 2014
ce4fe75
Fix attar accessibility of @parent_core and @logger
pitr-ch May 23, 2014
8217cb4
AdHoc calls message processing block with instance_exec and it accept…
pitr-ch May 23, 2014
b021a94
Add Actress specs
pitr-ch May 23, 2014
ae4331a
Do not allow running jobs with OneOnOne on executors which may averflow
pitr-ch May 24, 2014
dbd1144
Add configurable logging
pitr-ch May 24, 2014
b0a6884
fix core methods return values
pitr-ch May 24, 2014
c643e88
Expose terminated to public to be able to wait for termination
pitr-ch May 24, 2014
bd65cd7
Add spawn! method which raises when Context initialization fails
pitr-ch May 24, 2014
8d64ed1
Terminate all children on parent termination
pitr-ch May 24, 2014
cd22f67
log ignored exceptions on DEBUG level
pitr-ch May 24, 2014
465f0ef
More documentation
pitr-ch May 24, 2014
7ce883c
Test fixes
pitr-ch May 24, 2014
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ source 'https://rubygems.org'

gemspec


group :development do
gem 'rake', '~> 10.2.2'
gem 'countloc', '~> 0.4.0', platforms: :mri
Expand Down
1 change: 1 addition & 0 deletions lib/concurrent.rb
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
require 'concurrent/supervisor'
require 'concurrent/timer_task'
require 'concurrent/tvar'
require 'concurrent/actress'

# Modern concurrency tools for Ruby. Inspired by Erlang, Clojure, Scala, Haskell,
# F#, C#, Java, and classic concurrency patterns.
Expand Down
73 changes: 73 additions & 0 deletions lib/concurrent/actress.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
require 'concurrent/configuration'
require 'concurrent/executor/one_by_one'
require 'concurrent/ivar'
require 'concurrent/logging'

module Concurrent

# {include:file:lib/concurrent/actress/doc.md}
module Actress

require 'concurrent/actress/type_check'
require 'concurrent/actress/errors'
require 'concurrent/actress/core_delegations'
require 'concurrent/actress/envelope'
require 'concurrent/actress/reference'
require 'concurrent/actress/core'
require 'concurrent/actress/context'

require 'concurrent/actress/ad_hoc'

# @return [Reference, nil] current executing actor if any
def self.current
Thread.current[:__current_actress__]
end

# implements ROOT
class Root
include Context
# to allow spawning of new actors, spawn needs to be called inside the parent Actor
def on_message(message)
if message.is_a?(Array) && message.first == :spawn
spawn message[1], &message[2]
else
# ignore
end
end
end

# A root actor, a default parent of all actors spawned outside an actor
ROOT = Core.new(parent: nil, name: '/', class: Root).reference

# @param block for actress_class instantiation
# @param args see {.spawn_optionify}
def self.spawn(*args, &block)
if Actress.current
Core.new(spawn_optionify(*args).merge(parent: Actress.current), &block).reference
else
ROOT.ask([:spawn, spawn_optionify(*args), block]).value
end
end

# as {.spawn} but it'll raise when Actor not initialized properly
def self.spawn!(*args, &block)
spawn(spawn_optionify(*args).merge(initialized: ivar = IVar.new), &block).tap { ivar.no_error! }
end

# @overload spawn_optionify(actress_class, name, *args)
# @param [Context] actress_class to be spawned
# @param [String, Symbol] name of the instance, it's used to generate the path of the actor
# @param args for actress_class instantiation
# @overload spawn_optionify(opts)
# see {Core#initialize} opts
def self.spawn_optionify(*args)
if args.size == 1 && args.first.is_a?(Hash)
args.first
else
{ class: args[0],
name: args[1],
args: args[2..-1] }
end
end
end
end
14 changes: 14 additions & 0 deletions lib/concurrent/actress/ad_hoc.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
module Concurrent
module Actress
class AdHoc
include Context
def initialize(*args, &initializer)
@on_message = Type! initializer.call(*args), Proc
end

def on_message(message)
instance_exec message, &@on_message
end
end
end
end
96 changes: 96 additions & 0 deletions lib/concurrent/actress/context.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
module Concurrent
module Actress

# module used to define actor behaviours
# @example ping
# class Ping
# include Context
# def on_message(message)
# message
# end
# end
#
# Ping.spawn(:ping1).ask(:m).value #=> :m
module Context
include TypeCheck
include CoreDelegations

attr_reader :core

# @abstract override to define Actor's behaviour
# @param [Object] message
# @return [Object] a result which will be used to set the IVar supplied to Reference#ask
# @note self should not be returned (or sent to other actors), {#reference} should be used
# instead
def on_message(message)
raise NotImplementedError
end

def logger
core.logger
end

# @api private
def on_envelope(envelope)
@envelope = envelope
on_message envelope.message
ensure
@envelope = nil
end

# @see Actress.spawn
def spawn(*args, &block)
Actress.spawn(*args, &block)
end

# @see Core#children
def children
core.children
end

# @see Core#terminate!
def terminate!
core.terminate!
end

private

# @api private
def initialize_core(core)
@core = Type! core, Core
end

# @return [Envelope] current envelope, accessible inside #on_message processing
def envelope
@envelope or raise 'envelope not set'
end

def self.included(base)
base.extend ClassMethods
super base
end

module ClassMethods
# behaves as {Actress.spawn} but class_name is omitted
def spawn(name_or_opts, *args, &block)
Actress.spawn spawn_optionify(name_or_opts, *args), &block
end

# behaves as {Actress.spawn!} but class_name is omitted
def spawn!(name_or_opts, *args, &block)
Actress.spawn! spawn_optionify(name_or_opts, *args), &block
end

private

def spawn_optionify(name_or_opts, *args)
if name_or_opts.is_a? Hash
name_or_opts.merge class: self
else
{ class: self, name: name_or_opts, args: args }
end
end
end
end
end
end
Loading