async def maybe_open_pikerd( loglevel: Optional[str] = None, **kwargs, ) -> Union[tractor._portal.Portal, Services]: """If no ``pikerd`` daemon-root-actor can be found start it and yield up (we should probably figure out returning a portal to self though). """ if loglevel: get_console_log(loglevel) # subtle, we must have the runtime up here or portal lookup will fail async with maybe_open_runtime(loglevel, **kwargs): async with tractor.find_actor(_root_dname) as portal: # assert portal is not None if portal is not None: yield portal return # presume pikerd role since no daemon could be found at # configured address async with open_pikerd( loglevel=loglevel, debug_mode=kwargs.get('debug_mode', False), ) as _: # in the case where we're starting up the # tractor-piker runtime stack in **this** process # we return no portal to self. yield None
async def open_paperboi( fqsn: str, loglevel: str, ) -> Callable: ''' Spawn a paper engine actor and yield through access to its context. ''' broker, symbol, expiry = unpack_fqsn(fqsn) service_name = f'paperboi.{broker}' async with ( tractor.find_actor(service_name) as portal, tractor.open_nursery() as tn, ): # only spawn if no paperboi already is up # (we likely don't need more then one proc for basic # simulated order clearing) if portal is None: portal = await tn.start_actor( service_name, enable_modules=[__name__] ) async with portal.open_context( trades_dialogue, broker=broker, fqsn=fqsn, loglevel=loglevel, ) as (ctx, first): yield ctx, first
async def test_quote_streaming(tmx_symbols, loglevel, stream_what): """Set up option streaming using the broker daemon. """ brokermod = get_brokermod('questrade') async with tractor.find_actor('brokerd') as portal: async with tractor.open_nursery() as nursery: # only one per host address, spawns an actor if None if not portal: # no brokerd actor found portal = await nursery.start_actor( 'data_feed', rpc_module_paths=[ 'piker.brokers.data', 'piker.brokers.core' ], ) feed = DataFeed(portal, brokermod) if len(stream_what) > 1: # stream disparate symbol sets per task first, *tail = tmx_symbols symbols = ([first], tail) else: symbols = [tmx_symbols] async with trio.open_nursery() as n: for syms, func in zip(symbols, stream_what): n.start_soon(func, feed, syms) # stop all spawned subactors await nursery.cancel()
async def subs( which, pub_actor_name, seed=10, portal=None, task_status=trio.TASK_STATUS_IGNORED, ): if len(which) == 1: if which[0] == 'even': pred = is_even else: def pred(i): return not is_even(i) else: def pred(i): return isinstance(i, int) async with tractor.find_actor(pub_actor_name) as portal: stream = await portal.run( __name__, 'pubber', topics=which, seed=seed, ) task_status.started(stream) times = 10 count = 0 await stream.__anext__() async for pkt in stream: for topic, value in pkt.items(): assert pred(value) count += 1 if count >= times: break await stream.aclose() stream = await portal.run( __name__, 'pubber', topics=['odd'], seed=seed, ) await stream.__anext__() count = 0 # async with aclosing(stream) as stream: try: async for pkt in stream: for topic, value in pkt.items(): pass # assert pred(value) count += 1 if count >= times: break finally: await stream.aclose()
async def stream_from_single_subactor( arb_addr, start_method, stream_func, ): """Verify we can spawn a daemon actor and retrieve streamed data. """ # only one per host address, spawns an actor if None async with tractor.open_nursery( arbiter_addr=arb_addr, start_method=start_method, ) as nursery: async with tractor.find_actor('streamerd') as portals: if not portals: # no brokerd actor found portal = await nursery.start_actor( 'streamerd', enable_modules=[__name__], ) seq = range(10) with trio.fail_after(5): async with portal.open_stream_from( stream_func, sequence=list( seq), # has to be msgpack serializable ) as stream: # it'd sure be nice to have an asyncitertools here... iseq = iter(seq) ival = next(iseq) async for val in stream: assert val == ival try: ival = next(iseq) except StopIteration: # should cancel far end task which will be # caught and no error is raised await stream.aclose() await trio.sleep(0.3) # ensure EOC signalled-state translates # XXX: not really sure this is correct, # shouldn't it be a `ClosedResourceError`? try: await stream.__anext__() except StopAsyncIteration: # stop all spawned subactors await portal.cancel_actor()
async def find_service( service_name: str, ) -> Optional[tractor.Portal]: log.info(f'Scanning for service `{service_name}`') # attach to existing daemon by name if possible async with tractor.find_actor( service_name, arbiter_sockaddr=_registry_addr, ) as maybe_portal: yield maybe_portal
async def find_local_monitor(): """Establish a portal to a local monitor for triggering symbol changes. """ async with tractor.find_actor('monitor') as portal: if not portal: log.warn( "No monitor app could be found, no symbol link established..") else: log.info(f"Found {portal.channel.uid}") yield portal
async def maybe_spawn_brokerd_as_subactor(sleep=0.5, tries=10, loglevel=None): """If no ``brokerd`` daemon-actor can be found spawn one in a local subactor. """ async with tractor.open_nursery() as nursery: async with tractor.find_actor('brokerd') as portal: if not portal: log.info("No broker daemon could be found, spawning brokerd..") portal = await nursery.start_actor( 'brokerd', rpc_module_paths=_data_mods, loglevel=loglevel, ) yield portal
async def maybe_spawn_brokerd( brokername: str, sleep: float = 0.5, loglevel: Optional[str] = None, expose_mods: List = [], **tractor_kwargs, ) -> tractor._portal.Portal: """If no ``brokerd.{brokername}`` daemon-actor can be found, spawn one in a local subactor and return a portal to it. """ if loglevel: get_console_log(loglevel) # disable debugger in brokerd? # tractor._state._runtime_vars['_debug_mode'] = False tractor_kwargs['loglevel'] = loglevel brokermod = get_brokermod(brokername) dname = f'brokerd.{brokername}' async with tractor.find_actor(dname) as portal: # WTF: why doesn't this work? if portal is not None: yield portal else: # no daemon has been spawned yet log.info(f"Spawning {brokername} broker daemon") tractor_kwargs = getattr(brokermod, '_spawn_kwargs', {}) async with tractor.open_nursery() as nursery: try: # spawn new daemon portal = await nursery.start_actor( dname, enable_modules=_data_mods + [brokermod.__name__], loglevel=loglevel, **tractor_kwargs) async with tractor.wait_for_actor(dname) as portal: yield portal finally: # client code may block indefinitely so cancel when # teardown is invoked await nursery.cancel()
async def sleep_back_actor( actor_name, func_name, func_defined, exposed_mods, ): if actor_name: async with tractor.find_actor(actor_name) as portal: try: await portal.run(__name__, func_name) except tractor.RemoteActorError as err: if not func_defined: expect = AttributeError if not exposed_mods: expect = tractor.ModuleNotExposed assert err.type is expect raise else: await trio.sleep(float('inf'))
async def stream_from_single_subactor(): """Verify we can spawn a daemon actor and retrieve streamed data. """ async with tractor.find_actor('brokerd') as portals: if not portals: # only one per host address, spawns an actor if None async with tractor.open_nursery() as nursery: # no brokerd actor found portal = await nursery.start_actor( 'streamerd', rpc_module_paths=[__name__], statespace={'global_dict': {}}, ) seq = range(10) agen = await portal.run( __name__, 'stream_seq', # the func above sequence=list(seq), # has to be msgpack serializable ) # it'd sure be nice to have an asyncitertools here... iseq = iter(seq) ival = next(iseq) async for val in agen: assert val == ival try: ival = next(iseq) except StopIteration: # should cancel far end task which will be # caught and no error is raised await agen.aclose() await trio.sleep(0.3) try: await agen.__anext__() except StopAsyncIteration: # stop all spawned subactors await portal.cancel_actor()
async def say_hello(other_actor): await trio.sleep(1) # wait for other actor to spawn async with tractor.find_actor(other_actor) as portal: assert portal is not None return await portal.run(__name__, 'hi')