async def main(): context = RootContext() Serialization().register_file_descriptor(DESCRIPTOR) Remote().start("192.168.1.129", 12001) wg = asyncio.Event() message_count = 10000 props = Props.from_producer(lambda: LocalClient(0, message_count, wg, asyncio.get_event_loop())) pid = context.spawn(props) remote = PID(address="192.168.1.77:12000", id="remote") await context.request_future(remote, StartRemote(Sender=pid)) start = datetime.datetime.now() print('Starting to send') for i in range(message_count): await context.send(remote, Ping()) await wg.wait() elapsed = datetime.datetime.now() - start print(f'Elapsed {elapsed}') t = message_count * 2.0 / elapsed.total_seconds() print(f'Throughput {t} msg / sec') input()
async def main(): context = RootContext() props = Props.from_func(hello_function) pid = context.spawn(props) reply = await context.request_future(pid, HelloMessage('Hello')) print(reply)
async def main(): context = RootContext() props = Props.from_producer(HelloActor) pid = context.spawn(props) await context.send(pid, HelloMessage('Hello World!')) input()
async def start(argv): tracer = init_jaeger_tracer() opentracing.set_global_tracer(tracer) middleware = open_tracing_middleware.open_tracing_sender_middleware(tracer) Serialization().register_file_descriptor(DESCRIPTOR) Remote().start("127.0.0.1", 12001) server = PID(address='127.0.0.1:8000', id='chatserver') context = RootContext(MessageHeader(), [middleware]) props = OpenTracingFactory.get_props_with_open_tracing(Props.from_func(process_message), span_setup, span_setup, tracer) client = context.spawn(props) await context.send(server, Connect(sender=client)) nick = 'Alex' while True: text = input() if text == '/exit': return elif text.startswith('/nick '): new_nick = text.split(' ')[1] await context.send(server, NickRequest(old_user_name=nick, new_user_name=new_nick)) nick = new_nick else: await context.send(server, SayRequest(user_name=nick, message=text))
async def main(): tracer = init_jaeger_tracer() opentracing.set_global_tracer(tracer) context = RootContext() Serialization().register_file_descriptor(DESCRIPTOR) Remote().start("127.0.0.1", 8000) clients = [] async def process_message(ctx: AbstractContext): msg = ctx.message if isinstance(msg, Connect): print(f'Client {msg.sender} connected') clients.append(msg.sender) await ctx.send(msg.sender, Connected(message='Welcome!')) elif isinstance(msg, SayRequest): for client in clients: await ctx.send(client, SayResponse(user_name=msg.user_name, message=msg.message)) elif isinstance(msg, NickRequest): for client in clients: await ctx.send(client, NickResponse(old_user_name=msg.old_user_name, new_user_name=msg.new_user_name)) props = OpenTracingFactory.get_props_with_open_tracing(Props.from_func(process_message), span_setup, span_setup) context.spawn_named(props, 'chatserver') input()
async def test_pop_behavior_should_restore_pushed_behavior(): behavior = Behavior() async def func_1(ctx): if isinstance(ctx.message, str): async def func_2(ctx2): await ctx2.respond(42) behavior.unbecome_stacked() behavior.become_stacked(func_2) await ctx.respond(ctx.message) behavior.become(func_1) props = Props.from_func(behavior.receive_async) context = RootContext() pid = context.spawn(props) reply = await context.request_future(pid, "number") reply_after_push = await context.request_future(pid, None) reply_after_pop = await context.request_future( pid, "answertolifetheuniverseandeverything") assert reply + str( reply_after_push ) + reply_after_pop == "number42answertolifetheuniverseandeverything"
async def run_consistent_hash_pool_test(): context = RootContext() props = Router.new_consistent_hash_pool(my_actor_props, 5) pid = context.spawn(props) for i in range(10): await context.send(pid, Message('%s' % (i % 4)))
async def run_broadcast_pool_test(): context = RootContext() props = Router.new_broadcast_pool(my_actor_props, 5) for i in range(10): pid = context.spawn(props) await context.send(pid, Message('%s' % (i % 4)))
async def main(): context = RootContext() provider = InMemoryProvider() props = Props.from_producer(lambda: MyPersistenceActor(provider)) pid = context.spawn(props) input()
async def test_can_use_global_behaviour(): context = RootContext() test_actor_props = Props.from_producer(LightBulb) actor = context.spawn(test_actor_props) _ = await context.request_future(actor, PressSwitch()) assert await context.request_future(actor, HitWithHammer()) == "Smashed!" assert await context.request_future(actor, PressSwitch()) == "Broken" assert await context.request_future(actor, Touch()) == "OW!"
async def test_can_change_states(): test_actor_props = Props.from_producer(LightBulb) context = RootContext() actor = context.spawn(test_actor_props) assert await context.request_future(actor, PressSwitch()) == "Turning on" assert await context.request_future(actor, Touch()) == "Hot!" assert await context.request_future(actor, PressSwitch()) == "Turning off" assert await context.request_future(actor, Touch()) == "Cold"
async def run_round_robin_group_test(): context = RootContext() props = Router.new_round_robin_group([context.spawn(my_actor_props), context.spawn(my_actor_props), context.spawn(my_actor_props), context.spawn(my_actor_props)]) pid = context.spawn(props) for i in range(10): await context.send(pid, Message('%s' % (i % 4)))
async def main(): context = RootContext() pr = cProfile.Profile() while True: pid = context.spawn(props) pr.clear() pr.enable() response = await context.request_future( pid, Request(num=0, size=100, div=10)) pr.disable() pr.print_stats(sort='time') print(response) await context.stop_future(pid) await asyncio.sleep(0.5)
async def main(): tracer = init_jaeger_tracer() opentracing.set_global_tracer(tracer) GlobalEventStream.subscribe(process_dead_letter_event, DeadLetterEvent) context = RootContext(middleware=[open_tracing_sender_middleware()]) props = Props.from_producer(lambda: ChildActor()) props = OpenTracingFactory.get_props_with_open_tracing(props) actor = context.spawn(props) await context.send(actor, Hello(who="Alex")) await asyncio.sleep(1) await GlobalRootContext.stop_future(actor) input()
async def start(argv): host = None port = None opts, args = getopt.getopt(argv, "hp", ["host=", "port="]) for opt, arg in opts: if opt == '--host': host = arg elif opt == '--port': port = arg Serialization().register_file_descriptor(DESCRIPTOR) context = RootContext() Remote().start(host, port) props = Props().from_producer(lambda: EchoActor(host, port)) Remote().register_known_kind('EchoActor', props) context.spawn_named(props, "EchoActorInstance") input()
def __init__(self, number_of_iterations: int, interval_between_console_updates: int, uptime: float, refusal_probability: float, busy_probability: float, retry_attempts: int, verbose: bool): self._context = RootContext() self._number_of_iterations = number_of_iterations self._interval_between_console_updates = interval_between_console_updates self._uptime = uptime self._refusal_probability = refusal_probability self._busy_probability = busy_probability self._retry_attempts = retry_attempts self._verbose = verbose self._transfers = [] self._success_results = 0 self._failed_and_inconsistent_results = 0 self._failed_but_consistent_results = 0 self._unknown_results = 0 self._in_memory_provider = None
async def main(): context = RootContext() number_of_transfers = 5 interval_between_console_updates = 1 uptime = 99.99 retry_attempts = 0 refusal_probability = 0.01 busy_probability = 0.01 verbose = False props = Props.from_producer(lambda: Runner( number_of_transfers, interval_between_console_updates, uptime, refusal_probability, busy_probability, retry_attempts, verbose )).with_child_supervisor_strategy( OneForOneStrategy(lambda pid, reason: SupervisorDirective.Restart, retry_attempts, None)) print('Spawning runner') context.spawn_named(props, 'runner') input()
async def main(): context = RootContext() logging.basicConfig( format='%(name)s - %(levelname)s - %(message)s %(stack_info)s', level=logging.DEBUG, handlers=[logging.StreamHandler(sys.stdout)]) props = Props.from_producer( lambda: ParentActor()).with_child_supervisor_strategy( OneForOneStrategy(Decider.decide, 1, None)) actor = context.spawn(props) await context.send(actor, Hello('Alex')) await context.send(actor, Recoverable()) await context.send(actor, Fatal()) await asyncio.sleep(1) await context.stop(actor) input()
async def main(): root_context = RootContext() counter = itertools.count() next(counter) async def fn(context: AbstractContext): msg = context.message if isinstance(msg, Started): print(f'{datetime.today().strftime("%Y-%m-%d-%H.%M.%S")} Started') context.set_receive_timeout(timedelta(seconds=1)) elif isinstance(msg, ReceiveTimeout): print(f'{datetime.today().strftime("%Y-%m-%d-%H.%M.%S")} ReceiveTimeout: {next(counter)}') elif isinstance(msg, NoInfluence): print(f'{datetime.today().strftime("%Y-%m-%d-%H.%M.%S")} Received a no-influence message') elif isinstance(msg, str): print(f'{datetime.today().strftime("%Y-%m-%d-%H.%M.%S")} Received message: {msg}') props = Props.from_func(fn) pid = root_context.spawn(props) for i in range(6): await root_context.send(pid, 'hello') await asyncio.sleep(0.5) print('Hit [return] to send no-influence messages') input() for i in range(6): await root_context.send(pid, NoInfluence()) await asyncio.sleep(0.5) print('Hit [return] to send a message to cancel the timeout') input() await root_context.send(pid, 'cancel') print('Hit [return] to finish') input()
async def main(): async def child_fn(context: AbstractContext): print(f'{context.my_self.id}: MSG: {type(context.message)}') if isinstance(context.message, Started): raise Exception('child failure') child_props = Props.from_func(child_fn) async def root_fn(context: AbstractContext): print(f'{context.my_self.id}: MSG: {type(context.message)}') if isinstance(context.message, Started): context.spawn_named(child_props, 'child') elif isinstance(context.message, Terminated): print(f'Terminated {context.message.who}') root_props = Props.from_func(root_fn).with_child_supervisor_strategy( OneForOneStrategy(lambda pid, reason: SupervisorDirective.Escalate, 0, None)) root_context = RootContext() root_context.spawn_named(root_props, 'root') input()
async def main(): context = LoggingRootDecorator(RootContext()) async def fn(context: AbstractContext): message = context.message if isinstance(message, str): print(f'Inside Actor: {message}') await context.respond("Yo!") props = Props.from_func(fn).with_context_decorator([ lambda c: LoggingDecorator(c, 'logger1'), lambda c: LoggingDecorator(c, 'logger2') ]) pid = context.spawn(props) res = await context.request_future(pid, 'Hello') print(f'Got result {res}') input()
async def start(argv): context = RootContext() Serialization().register_file_descriptor(DESCRIPTOR) parsed_args = parse_args(argv) # await Cluster.start('MyCluster', parsed_args.server_name, 12002, SingleRemoteInstanceProvider('192.168.1.72', 12000)) await Cluster.start( 'MyCluster', parsed_args.server_name, 12001, ConsulProvider( ConsulClientConfiguration( f'http://{parsed_args.consul_url}:8500/'))) pid, sc = await Cluster.get_async("TheName", "HelloKind") while sc != ResponseStatusCode.OK: await asyncio.sleep(0.5) pid, sc = await Cluster.get_async("TheName", "HelloKind") res = await context.request_future(pid, HelloRequest()) print(res.message) await asyncio.sleep(timedelta(days=180).total_seconds()) print('Shutting Down...') await Cluster.shutdown()
async def main(): context = RootContext() Serialization().register_file_descriptor(DESCRIPTOR) Remote().start("192.168.1.77", 12000) context.spawn_named(Props.from_producer(lambda: EchoActor()), 'remote') input()
def __init__(self, context: AbstractSenderContext = RootContext()): self._context = context
async def main(): headers = MessageHeader({'TraceID': str(uuid.uuid4()), 'SpanID': str(uuid.uuid4())}) def get_middleware(next_middleware): async def process(context, target, envelope): new_envelope = envelope \ .with_header(key='TraceID', value=context.headers.get('TraceID')) \ .with_header(key='SpanID', value=str(uuid.uuid4())) \ .with_header(key='ParentSpanID', value=context.headers.get('SpanID')) print(' 1 Enter RootContext SenderMiddleware') print(' 1 TraceID: ' + new_envelope.header.get('TraceID')) print(' 1 SpanID: ' + new_envelope.header.get('SpanID')) print(' 1 ParentSpanID: ' + new_envelope.header.get('ParentSpanID')) await next_middleware(context, target, new_envelope) print(' 1 Exit RootContext SenderMiddleware - Send is async, this is out of order by design') return process root = RootContext(headers, [get_middleware]) async def actor_logic(context): if isinstance(context.message, str): print(' 3 Enter Actor') print(' 3 TraceID = ' + context.headers.get('TraceID')) print(' 3 SpanID = ' + context.headers.get('SpanID')) print(' 3 ParentSpanID = ' + context.headers.get('ParentSpanID')) print(' 3 actor got = %s:%s' % (str(type(context.message)), context.message)) await context.respond("World !") print(' 3 Exit Actor') def get_receive_middleware(next_middleware): async def process(context, envelope): if isinstance(envelope.message, str): new_envelope = envelope \ .with_header(key='TraceID', value=envelope.header.get('TraceID')) \ .with_header(key='SpanID', value=str(uuid.uuid4())) \ .with_header(key='ParentSpanID', value=envelope.header.get('SpanID')) print(' 2 Enter Actor ReceiverMiddleware') print(' 2 TraceID: ' + new_envelope.header.get('TraceID')) print(' 2 SpanID: ' + new_envelope.header.get('SpanID')) print(' 2 ParentSpanID: ' + new_envelope.header.get('ParentSpanID')) await next_middleware(context, new_envelope) print(' 2 Exit Actor ReceiverMiddleware') else: await next_middleware(context, envelope) return process def get_sender_middleware(next_middleware): async def process(context, target, envelope): new_envelope = envelope \ .with_header(key='TraceID', value=context.headers.get('TraceID')) \ .with_header(key='SpanID', value=str(uuid.uuid4())) \ .with_header(key='ParentSpanID', value=context.headers.get('SpanID')) print(' 4 Enter Actor SenderMiddleware') print(' 4 TraceID: ' + new_envelope.header.get('TraceID')) print(' 4 SpanID: ' + new_envelope.header.get('SpanID')) print(' 4 ParentSpanID: ' + new_envelope.header.get('ParentSpanID')) await next_middleware(context, target, envelope) print(' 4 Exit Actor SenderMiddleware') return process actor = Props.from_func(actor_logic)\ .with_receive_middleware([get_receive_middleware])\ .with_sender_middleware([get_sender_middleware]) pid = root.spawn(actor) print('0 TraceID: ' + root.headers.get('TraceID')) print('0 SpanID: ' + root.headers.get('SpanID')) print('0 ParentSpanID: ' + root.headers.get('ParentSpanID', '')) res = await root.request_future(pid, "hello") print('Got result ' + res) await asyncio.sleep(0.5)
import asyncio import logging import threading from datetime import timedelta import pytest from protoactor.actor.actor import Actor from protoactor.actor.actor_context import RootContext, AbstractContext from protoactor.actor.props import Props from protoactor.router.messages import RemoveRoutee, GetRoutees, AddRoutee, BroadcastMessage from protoactor.router.router import Router context = RootContext() timeout = timedelta(milliseconds=1000) my_actor_props = Props.from_producer(lambda: MyTestActor()) @pytest.mark.asyncio async def test_broadcast_group_router_all_routees_receive_messages(): router, routee1, routee2, routee3 = create_broadcast_group_router_with3_routees( ) await context.send(router, 'hello') assert await context.request_future(routee1, 'received?', timeout) == 'hello' assert await context.request_future(routee2, 'received?', timeout) == 'hello' assert await context.request_future(routee3, 'received?', timeout) == 'hello'
async def main(): context = RootContext() props = Props.from_producer(ScheduleActor) pid = context.spawn(props) input()
class Runner(Actor): def __init__(self, number_of_iterations: int, interval_between_console_updates: int, uptime: float, refusal_probability: float, busy_probability: float, retry_attempts: int, verbose: bool): self._context = RootContext() self._number_of_iterations = number_of_iterations self._interval_between_console_updates = interval_between_console_updates self._uptime = uptime self._refusal_probability = refusal_probability self._busy_probability = busy_probability self._retry_attempts = retry_attempts self._verbose = verbose self._transfers = [] self._success_results = 0 self._failed_and_inconsistent_results = 0 self._failed_but_consistent_results = 0 self._unknown_results = 0 self._in_memory_provider = None def __create_account(self, name: str) -> PID: account_props = Props.from_producer( lambda: Account(name, self._uptime, self._refusal_probability, self ._busy_probability)) return self._context.spawn_named(account_props, name) async def receive(self, context: AbstractContext) -> None: msg = context.message if isinstance(msg, SuccessResult): self._success_results += 1 await self.__check_for_completion(msg.pid) elif isinstance(msg, UnknownResult): self._unknown_results += 1 await self.__check_for_completion(msg.pid) elif isinstance(msg, FailedAndInconsistent): self._failed_and_inconsistent_results += 1 await self.__check_for_completion(msg.pid) elif isinstance(msg, FailedButConsistentResult): self._failed_but_consistent_results += 1 await self.__check_for_completion(msg.pid) elif isinstance(msg, Started): self._in_memory_provider = InMemoryProvider() def every_nth_action(i: int): print(f'Started {i}/{self._number_of_iterations} processes') def every_action(i: int, nth: bool): j = i from_account = self.__create_account(f'FromAccount{j}') to_account = self.__create_account(f'ToAccount{j}') actor_name = f'Transfer Process {j}' persistance_id = f'Transfer Process {j}' factory = TransferFactory(context, self._in_memory_provider, self._uptime, self._retry_attempts) transfer = factory.create_transfer(actor_name, from_account, to_account, 10, persistance_id) self._transfers.append(transfer) if i == self._number_of_iterations and not nth: print(f'Started {j}/{self._number_of_iterations} proesses') ForWithProgress(self._number_of_iterations, self._interval_between_console_updates, True, False).every_nth(every_nth_action, every_action) async def __check_for_completion(self, pid: PID): self._transfers.remove(pid) remaining = len(self._transfers) if self._number_of_iterations >= self._interval_between_console_updates: print('.') if remaining % (self._number_of_iterations / self._interval_between_console_updates) == 0: print() print(f'{remaining} processes remaining') else: print(f'{remaining} processes remaining') if remaining == 0: await asyncio.sleep(0.25) print() print( f'RESULTS for {self._uptime}% uptime, {self._refusal_probability}% chance of refusal, ' f'{self._busy_probability}% of being busy and {self._retry_attempts} retry attempts:' ) print( f'{self.__as_percentage(self._number_of_iterations, self._success_results)}% ' f'({self._success_results}/{self._number_of_iterations}) successful transfers' ) print( f'{self.__as_percentage(self._number_of_iterations, self._failed_but_consistent_results)}% ' f'({self._failed_but_consistent_results}/{self._number_of_iterations}) ' f'failures leaving a consistent system') print( f'{self.__as_percentage(self._number_of_iterations, self._failed_and_inconsistent_results)}% ' f'({self._failed_and_inconsistent_results}/{self._number_of_iterations}) ' f'failures leaving an inconsistent system') print( f'{self.__as_percentage(self._number_of_iterations, self._unknown_results)}% ' f'({self._unknown_results}/{self._number_of_iterations}) unknown results' ) if self._verbose: for stream in self._in_memory_provider.events: print() print(f'Event log for {stream.key}') for event in stream.value: print(event.value) def __as_percentage(self, number_of_iterations: float, results: float): return (results / number_of_iterations) * 100
import threading import uuid import pytest from protoactor.actor.actor import Actor from protoactor.actor.actor_context import AbstractContext, RootContext from protoactor.actor.props import Props from protoactor.persistence.persistence import Persistence from protoactor.persistence.snapshot_strategies.interval_strategy import IntervalStrategy from protoactor.persistence.providers.in_memory_provider import InMemoryProvider from tests.persistence.test_example_persistent_actor import Multiplied, Multiply from tests.test_fixtures.mock_mailbox import MockMailbox root_context = RootContext() @pytest.mark.asyncio async def test_given_an_interval_strategy_should_save_snapshot_accordingly(): threading_events, pid, _, actor_id, provider_state = create_test_actor(IntervalStrategy(1)) await root_context.send(pid, Multiply(2)) threading_events['process_multiply'].wait() threading_events['process_multiply'].clear() await root_context.send(pid, Multiply(2)) threading_events['process_multiply'].wait() threading_events['process_multiply'].clear() await root_context.send(pid, Multiply(2)) threading_events['process_multiply'].wait()