def spawn(actor, name=None, ip='localhost', **kwargs): """ Utility function to start a process actor and initialize it """ if name is not None: with ActorRef((name, ip, None)) as ref: # Do not start if it's already alive if ref.is_alive(): return ProcessActorProxy(*ref.full_address()) a = actor() class Wait(Actor): def act(self): self.success = True self.receive( finished_init=None, timed_out=lambda _: setattr(self, 'success', False), timeout=5) return self.success with ActorRef(a.remote_addr) as ref, Wait() as wait: kwargs['ip'] = ip ref.init(reply_to=wait, **kwargs) if wait.act(): remote = list(a.remote_addr) remote[1] = ip return ProcessActorProxy(remote, a.pid) else: raise SpawnTimeoutError('failed to init remote process')
def tick(self, msg): print('tick', self.my_name, self.c) self.c += 1 with ActorRef(msg.reply_to) as sender: sender.tick(reply_to=self) if self.c == self.max: with ActorRef(self.report_to) as ref: ref.report( name=self.my_name, start_time=self.starting_time, end_time=time.time() ) self.receive()
def run(): with Wait() as w, \ spawn(Collector, wait=w.address()) as collector, \ spawn(Ticker, my_name='Ping', c=0, max=10, report_to=collector.address()) as ping, \ spawn(Ticker, my_name='Pong', c=0, max=10, report_to=collector.address()) as pong, \ ActorRef(ping) as ping_ref, \ ActorRef(pong) as pong_ref: print('Starting') ping_ref.set_start_time() pong_ref.set_start_time() ping_ref.tick(reply_to=pong_ref) w.wait()
def test_inbox(namebroker, threaded_actor, answer_actor): with ActorRef(threaded_actor.address()) as t: t.foo() t.bar() t.reply5(reply_to=answer_actor) result = answer_actor.act() assert result == [5]
def test_many_msgs(namebroker): # Send many msgs to one actor, collect them and count them class A(ThreadedActor): def act(self): self.results = {} try: while True: self.receive(add=self.add) except ActorFinished: pass def add(self, msg): self.results[msg['i']] = 1 if list(sorted(self.results.keys())) == list(range(100)): with ActorRef(msg['reply_to']) as sender: sender.got_all() class B(Actor): def act(self): result = [] self.receive(got_all=lambda msg: result.append(True), timed_out=lambda msg: result.append(False), timeout=2) return result # Create many instances to check the pipes are refreshed for each instance actors = [A() for i in range(4)] collector = B() x_ref = ActorRef(actors[-1].address()) for i in range(100): x_ref.add(i=i, reply_to=collector) result = collector.act() assert result == [True] [x.close() for x in actors] collector.close()
def test_timeout_zero_no_match(data_actor): with ActorRef(data_actor.address()) as a_ref: a_ref.bar(data=2) while data_actor.inbox.qsize() != 1: time.sleep(0.1) for _ in range(4): result = data_actor.act() assert result is None
def test_timeout_zero(data_actor): with ActorRef(data_actor.address()) as a_ref: a_ref.foo(data=1) while True: result = data_actor.act() if result is not None: assert result == 1 return time.sleep(0.1)
def test_new_api_2(namebroker): class A(Actor): pass with A() as a, ActorRef(a.address()) as a_ref: with pytest.raises(TypeError): a_ref() a_ref.foo() with pytest.raises(TypeError): a_ref()
def test_none_method(): class A(Actor): def act(self): self.receive(foo=None) return True with A() as a, ActorRef(a.address()) as a_ref: a_ref.foo() result = a.act() assert result
def test_timeout_zero_2(data_actor): with ActorRef(data_actor.address()) as a_ref: a_ref.bar() a_ref.baz() a_ref.foo(data=1) a_ref.gii() while data_actor.inbox.qsize() < 4: time.sleep(0.1) result = data_actor.act() assert result == 1
def remote_init(self, msg): """ Save addresses of other actors we want this process to know """ del msg['tag'] for name in msg: setattr(self, name, msg[name]) with ActorRef(msg['reply_to']) as sender: sender.finished_init()
def test_attribute_access(): class A(ThreadedActor): def act(self): self.receive(echo=self.echo) def echo(self, msg): with ActorRef(msg.reply_to) as sender: sender.reply(x=4) with ThreadedActor.spawn(A) as a, ActorRef(a) as a_ref: result = a_ref.sync('echo') assert result['x'] == 4
def test_wildcard(namebroker): class A(Actor): def act(self): result = [] self.receive( _ = lambda msg: result.append(msg['tag'])) return result with A() as a, ActorRef(a.address()) as a_ref: a_ref.foo() result = a.act() assert result == ['foo']
def __exit__(self, exc_type, exc_value, traceback): """ Actor context closes it on exit """ try: with ActorRef(self.address()) as myself: myself.close_actor() except PipeException: # If actor was already closed, ignore error from the # reference trying to ping the actor pass
def test_alive_not_acting(): class A(Actor): def act(self): self.receive(_=self.read_value('tag')) return self.tag with A() as a, ActorRef(a.address()) as a_ref: alive = a_ref.is_alive() assert alive a_ref.foo() result = a.act() assert result == 'foo'
def test_sync_call(): class T(ThreadedActor): def act(self): self.receive(sync_test=self.sync_test) def sync_test(self, msg): with ActorRef(msg['reply_to']) as sender: sender.reply(got=msg) with T() as t, ActorRef(t.address()) as t_ref: assert t_ref.is_alive() answer = t_ref.sync('sync_test', x=5) assert answer['got']['tag'] == 'sync_test' assert answer['got']['x'] == 5
def test_new_api(namebroker): class A(Actor): def act(self): self.receive( foo = self.foo) return self._msg def foo(self, msg): self._msg = msg with A() as a, ActorRef(a.address()) as a_ref: a_ref.foo(bar=3, baz='baz') msg = a.act() assert (msg['tag'] == 'foo' and msg['bar'] == 3 and msg['baz'] == 'baz')
def test_process_close(): with ProcessActor.spawn(EchoProcessActor) as p, ActorRef(p.address()) as p_ref: assert p_ref.is_alive() p_ref.close_actor() assert not p_ref.is_alive() for _ in range(200): try: if os.waitpid(p.pid, os.WNOHANG) == (0, 0): break except ChildProcessError: break time.sleep(0.01) else: assert False
def test_close_actor_and_ref(): class Wait(Actor): def act(self): self.receive(_=None) class T(ThreadedActor): def act(self): self.receive() with T() as t, Wait() as w, ActorRef(t.address()) as t_ref: alive = t_ref.is_alive() assert alive t_ref.close_actor(confirm_to=w.address()) w.act() not_alive = not t_ref.is_alive() assert not_alive
def test_close_with_confirmation(threaded_actor): class A(Actor): def act(self): self.receive(_ = self.read_value('tag')) return self.tag class T(ThreadedActor): def act(self): self.receive() with A() as a, T() as t, ActorRef(t.address()) as t_ref: alive = t_ref.is_alive() assert alive t_ref.close_actor(confirm_to=a.address()) result = a.act() assert result == 'closed' assert not t_ref.is_alive()
def test_timeout_eating_msgs(): result = [True] class A(Actor): def act(self): self.receive(timeout=0.1) def act2(self): self.receive( bar = lambda msg: None, timed_out = lambda msg: result.append(False), timeout = 0.1) with A() as a, ActorRef(a.address()) as a_ref: a_ref.bar() while a.inbox.qsize() != 1: time.sleep(0.1) a.act() a.act2() assert result[-1]
def test_threaded_spawn_with_args_fast(): class T(ThreadedActor): def act(self): assert self.x == 0 self.receive(get_x=self.get_x) def get_x(self, msg): with ActorRef(msg.reply_to) as sender: sender.reply(x=self.x) class W(Actor): def act(self): self.x = 1 self.receive( reply=self.read_value('x'), timeout=0.5 ) return self.x with ThreadedActor.spawn(T, x=0) as t, ActorRef(t) as t_ref, W() as w: t_ref.get_x(reply_to=w) result = w.act() assert result == 0
def test_threaded_spawn_with_args(): class T(ThreadedActor): def act(self): self.receive( args = self.args ) def args(self, msg): with ActorRef(msg['reply_to']) as sender: sender.reply(x=self.x, k=self.k) class A(Actor): def act(self): self.receive( reply = self.reply ) return self.x, self.k def reply(self, msg): self.x = msg['x'] self.k = msg['k'] with ThreadedActor.spawn(T, x=5, k='a') as t, ActorRef(t.address()) as t_ref, A() as a: assert t_ref.is_alive() t_ref.args(reply_to=a.address()) result = a.act() assert result == (5, 'a')
def echo(self, msg): with ActorRef(msg.reply_to) as sender: sender.reply(x=4)
def test_ref_with_actor(threaded_actor): with ActorRef(threaded_actor) as t_ref: assert t_ref.address() == threaded_actor.address()
def __init__(self): super(PEcho, self).__init__() def act(self): while True: self.receive(_=self.do_pecho) def do_pecho(self, msg): print('Process Echo:') print(msg) if __name__ == '__main__': _, wait_name, actor_class, actor_module, class_dir = sys.argv sys.path.insert(0, class_dir) mod = importlib.import_module(actor_module) cls = getattr(mod, actor_class) # Signal the base class ``ProcessActor`` to not start a new # subprocess (we are already in it!) cls.launch = False with cls() as actor, ActorRef(wait_name, remote=False) as wait: # Tell parent to keep going wait.ok(spawn_address=actor.address(), pid=os.getpid()) # The new process ends when the client's actor finishes its # ``act`` method. try: actor._act() except KeyboardInterrupt: pass
def test_ref_with_ref(threaded_actor): with ActorRef(threaded_actor) as t_ref: with ActorRef(t_ref) as x_ref: assert t_ref.address() == x_ref.address()
def test_ref_with_proxy(process_actor): with ActorRef(process_actor) as ref: assert ref.is_alive()
def echo(self, msg): with ActorRef(msg['reply_to']) as sender: del msg['tag'] sender.reply(**msg)
def test_reply_to_proxy(process_actor): with ActorRef(process_actor) as ref: ref.foo(reply_to=process_actor) assert ref.is_alive()