async def test_create_actor_pool(): start_method = os.environ.get('POOL_START_METHOD', 'forkserver') \ if sys.platform != 'win32' else None pool = await create_actor_pool('127.0.0.1', pool_cls=MainActorPool, n_process=2, subprocess_start_method=start_method) async with pool: # test global router global_router = Router.get_instance() # global router should not be the identical one with pool's router assert global_router is not pool.router assert pool.external_address in global_router._curr_external_addresses assert pool.external_address in global_router._mapping ctx = get_context() # actor on main pool actor_ref = await ctx.create_actor(TestActor, uid='test-1', address=pool.external_address) assert await actor_ref.add(3) == 3 assert await actor_ref.add(1) == 4 assert (await ctx.has_actor(actor_ref)) is True assert (await ctx.actor_ref(actor_ref)) == actor_ref # test cancel task = asyncio.create_task(actor_ref.sleep(20)) await asyncio.sleep(0) task.cancel() assert await task == 5 await ctx.destroy_actor(actor_ref) assert (await ctx.has_actor(actor_ref)) is False for f in actor_ref.add, ctx.actor_ref, ctx.destroy_actor: with pytest.raises(ActorNotExist): await f(actor_ref) # actor on sub pool actor_ref1 = await ctx.create_actor(TestActor, uid='test-main', address=pool.external_address) actor_ref2 = await ctx.create_actor(TestActor, uid='test-2', address=pool.external_address, allocate_strategy=RandomSubPool()) assert (await ctx.actor_ref(uid='test-2', address=actor_ref2.address)) == actor_ref2 main_ref = await ctx.actor_ref(uid='test-main', address=actor_ref2.address) assert main_ref.address == pool.external_address main_ref = await ctx.actor_ref(actor_ref1) assert main_ref.address == pool.external_address assert actor_ref2.address != actor_ref.address assert await actor_ref2.add(3) == 3 assert await actor_ref2.add(1) == 4 with pytest.raises(RuntimeError): await actor_ref2.return_cannot_unpickle() assert (await ctx.has_actor(actor_ref2)) is True assert (await ctx.actor_ref(actor_ref2)) == actor_ref2 # test cancel task = asyncio.create_task(actor_ref2.sleep(20)) start = time.time() await asyncio.sleep(0) task.cancel() assert await task == 5 assert time.time() - start < 3 await ctx.destroy_actor(actor_ref2) assert (await ctx.has_actor(actor_ref2)) is False # after pool shutdown, global router must has been cleaned global_router = Router.get_instance() assert len(global_router._curr_external_addresses) == 0 assert len(global_router._mapping) == 0
async def test_sub_actor_pool(notify_main_pool): notify_main_pool.return_value = None config = ActorPoolConfig() ext_address0 = f'127.0.0.1:{get_next_port()}' ext_address1 = f'127.0.0.1:{get_next_port()}' _add_pool_conf(config, 0, 'main', 'unixsocket:///0', ext_address0) _add_pool_conf(config, 1, 'sub', 'unixsocket:///1', ext_address1) pool = await SubActorPool.create({ 'actor_pool_config': config, 'process_index': 1 }) await pool.start() create_actor_message = CreateActorMessage( new_message_id(), TestActor, b'test', tuple(), dict(), AddressSpecified(pool.external_address)) message = await pool.create_actor(create_actor_message) assert message.message_type == MessageType.result actor_ref = message.result assert actor_ref.address == pool.external_address assert actor_ref.uid == b'test' has_actor_message = HasActorMessage( new_message_id(), actor_ref) assert (await pool.has_actor(has_actor_message)).result is True actor_ref_message = ActorRefMessage( new_message_id(), actor_ref) assert (await pool.actor_ref(actor_ref_message)).result == actor_ref tell_message = TellMessage( new_message_id(), actor_ref, ('add', 0, (1,), dict())) message = await pool.tell(tell_message) assert message.result is None send_message = SendMessage( new_message_id(), actor_ref, ('add', 0, (3,), dict())) message = await pool.send(send_message) assert message.result == 4 # test error message # type mismatch send_message = SendMessage( new_message_id(), actor_ref, ('add', 0, ('3',), dict())) result = await pool.send(send_message) assert result.message_type == MessageType.error assert isinstance(result.error, TypeError) send_message = SendMessage( new_message_id(), create_actor_ref(actor_ref.address, 'non_exist'), ('add', 0, (3,), dict())) result = await pool.send(send_message) assert isinstance(result.error, ActorNotExist) # test send message and cancel it send_message = SendMessage( new_message_id(), actor_ref, ('sleep', 0, (20,), dict())) result_task = asyncio.create_task(pool.send(send_message)) await asyncio.sleep(0) start = time.time() cancel_message = CancelMessage( new_message_id(), actor_ref.address, send_message.message_id) cancel_task = asyncio.create_task(pool.cancel(cancel_message)) result = await asyncio.wait_for(cancel_task, 3) assert result.message_type == MessageType.result assert result.result is True result = await result_task # test time assert time.time() - start < 3 assert result.message_type == MessageType.result assert result.result == 5 # test processing message on background async with await pool.router.get_client(pool.external_address) as client: send_message = SendMessage( new_message_id(), actor_ref, ('add', 0, (5,), dict())) await client.send(send_message) result = await client.recv() assert result.result == 9 send_message = SendMessage( new_message_id(), actor_ref, ('add', 0, ('5',), dict())) await client.send(send_message) result = await client.recv() assert isinstance(result.error, TypeError) destroy_actor_message = DestroyActorMessage( new_message_id(), actor_ref) message = await pool.destroy_actor(destroy_actor_message) assert message.result == actor_ref.uid # send destroy failed message = await pool.destroy_actor(destroy_actor_message) assert isinstance(message.error, ActorNotExist) message = await pool.has_actor(has_actor_message) assert not message.result # test sync config _add_pool_conf(config, 1, 'sub', 'unixsocket:///1', f'127.0.0.1:{get_next_port()}') sync_config_message = ControlMessage( new_message_id(), '', ControlMessageType.sync_config, config) message = await pool.handle_control_command(sync_config_message) assert message.result is True # test get config get_config_message = ControlMessage( new_message_id(), '', ControlMessageType.get_config, None) message = await pool.handle_control_command(get_config_message) config2 = message.result assert config.as_dict() == config2.as_dict() assert pool.router._mapping == Router.get_instance()._mapping assert pool.router._curr_external_addresses == \ Router.get_instance()._curr_external_addresses stop_message = ControlMessage( new_message_id(), '', ControlMessageType.stop, None) message = await pool.handle_control_command(stop_message) assert message.result is True await pool.join(.05) assert pool.stopped