async def _call_later( timeout: float, callback: Callable, task_status: trio._core._run._TaskStatus = trio.TASK_STATUS_IGNORED, ) -> None: cancel_scope = trio.CancelScope() task_status.started(cancel_scope) with cancel_scope: await trio.sleep(timeout) cancel_scope.shield = True await callback()
async def worker_serve( app: Type[ASGIFramework], config: Config, *, sockets: Optional[List[socket]] = None, shutdown_event: Optional[EventType] = None, task_status: trio._core._run._TaskStatus = trio.TASK_STATUS_IGNORED, ) -> None: lifespan = Lifespan(app, config) reload_ = False async with trio.open_nursery() as lifespan_nursery: await lifespan_nursery.start(lifespan.handle_lifespan) await lifespan.wait_for_startup() try: async with trio.open_nursery() as nursery: if config.use_reloader: nursery.start_soon(observe_changes, trio.sleep) if shutdown_event is not None: nursery.start_soon(check_shutdown, shutdown_event, trio.sleep) if sockets is None: sockets = config.create_sockets() for sock in sockets: sock.listen(config.backlog) listeners = [ trio.SocketListener(trio.socket.from_stdlib_socket(sock)) for sock in sockets ] if config.ssl_enabled: listeners = [ trio.ssl.SSLListener(tcp_listener, config.create_ssl_context(), https_compatible=True) for tcp_listener in listeners ] task_status.started() await trio.serve_listeners(partial(serve_stream, app, config), listeners) except MustReloadException: reload_ = True except (Shutdown, KeyboardInterrupt): pass finally: await lifespan.wait_for_shutdown() lifespan_nursery.cancel_scope.cancel() if reload_: restart()
async def run( self, task_status: trio._core._run._TaskStatus = trio.TASK_STATUS_IGNORED ) -> None: from ..protocol.quic import QuicProtocol # h3/Quic is an optional part of Hypercorn task_status.started() server = parse_socket_addr(self.socket.family, self.socket.getsockname()) async with TaskGroup() as task_group: self.protocol = QuicProtocol( self.app, self.config, self.context, task_group, server, self.protocol_send ) while not self.context.terminated or not self.protocol.idle: data, address = await self.socket.recvfrom(MAX_RECV) await self.protocol.handle(RawData(data=data, address=address))
async def handle_lifespan( self, *, task_status: trio._core._run._TaskStatus = trio.TASK_STATUS_IGNORED ) -> None: task_status.started() scope = {"type": "lifespan", "asgi": {"spec_version": "2.0"}} try: await invoke_asgi(self.app, scope, self.asgi_receive, self.asgi_send) except LifespanFailure: # Lifespan failures should crash the server raise except Exception: self.supported = False await self.config.log.exception( "ASGI Framework Lifespan error, continuing without Lifespan support" ) finally: await self.app_send_channel.aclose() await self.app_receive_channel.aclose()
async def worker_serve( app: ASGIFramework, config: Config, *, sockets: Optional[Sockets] = None, shutdown_trigger: Optional[Callable[..., Awaitable[None]]] = None, task_status: trio._core._run._TaskStatus = trio.TASK_STATUS_IGNORED, ) -> None: config.set_statsd_logger_class(StatsdLogger) lifespan = Lifespan(app, config) reload_ = False async with trio.open_nursery() as lifespan_nursery: await lifespan_nursery.start(lifespan.handle_lifespan) await lifespan.wait_for_startup() try: async with trio.open_nursery() as nursery: if config.use_reloader: nursery.start_soon(observe_changes, trio.sleep) if shutdown_trigger is not None: nursery.start_soon(raise_shutdown, shutdown_trigger) if sockets is None: sockets = config.create_sockets() for sock in sockets.secure_sockets: sock.listen(config.backlog) for sock in sockets.insecure_sockets: sock.listen(config.backlog) ssl_context = config.create_ssl_context() listeners = [] binds = [] for sock in sockets.secure_sockets: listeners.append( trio.SSLListener( trio.SocketListener( trio.socket.from_stdlib_socket(sock)), ssl_context, https_compatible=True, )) bind = repr_socket_addr(sock.family, sock.getsockname()) binds.append(f"https://{bind}") await config.log.info( f"Running on https://{bind} (CTRL + C to quit)") for sock in sockets.insecure_sockets: listeners.append( trio.SocketListener( trio.socket.from_stdlib_socket(sock))) bind = repr_socket_addr(sock.family, sock.getsockname()) binds.append(f"http://{bind}") await config.log.info( f"Running on http://{bind} (CTRL + C to quit)") for sock in sockets.quic_sockets: await nursery.start( UDPServer(app, config, sock, nursery).run) bind = repr_socket_addr(sock.family, sock.getsockname()) await config.log.info( f"Running on https://{bind} (QUIC) (CTRL + C to quit)") task_status.started(binds) await trio.serve_listeners(partial(TCPServer, app, config), listeners, handler_nursery=lifespan_nursery) except MustReloadException: reload_ = True except (Shutdown, KeyboardInterrupt): pass finally: try: await trio.sleep(config.graceful_timeout) except (Shutdown, KeyboardInterrupt): pass await lifespan.wait_for_shutdown() lifespan_nursery.cancel_scope.cancel() if reload_: restart()
async def update_quotes( nursery: trio._core._run.Nursery, formatter: Callable, widgets: dict, agen: AsyncGeneratorType, symbol_data: dict, first_quotes: dict, task_status: trio._core._run._TaskStatus = trio.TASK_STATUS_IGNORED, ): """Process live quotes by updating ticker rows. """ log.debug("Initializing UI update loop") table = widgets['table'] flash_keys = {'low', 'high'} async def revert_cells_color(cells): await trio.sleep(0.3) for cell in cells: cell.background_color = _black_rgba def color_row(row, record, cells): hdrcell = row.get_cell('symbol') chngcell = row.get_cell('%') # determine daily change color percent_change = record.get('%') if percent_change is not None and percent_change != chngcell: daychange = float(percent_change) if daychange < 0.: color = colorcode('red2') elif daychange > 0.: color = colorcode('forestgreen') else: color = colorcode('gray') # if the cell has been "highlighted" make sure to change its color if hdrcell.background_color != [0]*4: hdrcell.background_color = color # update row header and '%' cell text color chngcell.color = color hdrcell.color = color # briefly highlight bg of certain cells on each trade execution unflash = set() tick_color = None last = cells.get('last') if not last: vol = cells.get('volume') if not vol: return # no trade exec took place # flash gray on volume tick # (means trade exec @ current price) last = row.get_cell('last') tick_color = colorcode('gray') else: tick_color = last.color last.background_color = tick_color unflash.add(last) # flash the size cell size = row.get_cell('size') size.background_color = tick_color unflash.add(size) # flash all other cells for key in flash_keys: cell = cells.get(key) if cell: cell.background_color = cell.color unflash.add(cell) # revert flash state momentarily nursery.start_soon(revert_cells_color, unflash) # initial coloring to_sort = set() for quote in first_quotes: row = table.get_row(quote['symbol']) row.update(quote) color_row(row, quote, {}) to_sort.add(row.widget) table.render_rows(to_sort) log.debug("Finished initializing update loop") task_status.started() # real-time cell update loop async for quotes in agen: # new quotes data only to_sort = set() for symbol, quote in quotes.items(): row = table.get_row(symbol) # don't red/green the header cell in ``row.update()`` quote.pop('symbol') quote.pop('key') # determine if sorting should happen sort_key = table.sort_key last = row.get_field(sort_key) new = quote.get(sort_key, last) if new != last: to_sort.add(row.widget) # update and color cells = row.update(quote) color_row(row, quote, cells) if to_sort: table.render_rows(to_sort) log.debug("Waiting on quotes") log.warn("Data feed connection dropped")
async def _async_main( self, accept_addr: Tuple[str, int], arbiter_addr: Optional[Tuple[str, int]] = None, parent_addr: Optional[Tuple[str, int]] = None, task_status: trio._core._run._TaskStatus = trio.TASK_STATUS_IGNORED, ) -> None: """Start the channel server, maybe connect back to the parent, and start the main task. A "root-most" (or "top-level") nursery for this actor is opened here and when cancelled effectively cancels the actor. """ arbiter_addr = arbiter_addr or self._arb_addr registered_with_arbiter = False try: async with trio.open_nursery() as nursery: self._root_nursery = nursery # Startup up channel server host, port = accept_addr await nursery.start( partial(self._serve_forever, accept_host=host, accept_port=port)) if parent_addr is not None: try: # Connect back to the parent actor and conduct initial # handshake (From this point on if we error, ship the # exception back to the parent actor) chan = self._parent_chan = Channel( destaddr=parent_addr, ) await chan.connect() # initial handshake, report who we are, who they are await _do_handshake(self, chan) except OSError: # failed to connect log.warning( f"Failed to connect to parent @ {parent_addr}," " closing server") await self.cancel() self._parent_chan = None # handle new connection back to parent nursery.start_soon(self._process_messages, self._parent_chan) # load exposed/allowed RPC modules # XXX: do this **after** establishing connection to parent # so that import errors are properly propagated upwards self.load_modules() # register with the arbiter if we're told its addr log.debug(f"Registering {self} for role `{self.name}`") async with get_arbiter(*arbiter_addr) as arb_portal: await arb_portal.run('self', 'register_actor', uid=self.uid, sockaddr=self.accept_addr) registered_with_arbiter = True task_status.started() log.debug("Waiting on root nursery to complete") # blocks here as expected until the channel server is # killed (i.e. this actor is cancelled or signalled by the parent) except Exception as err: if not registered_with_arbiter: log.exception( f"Actor errored and failed to register with arbiter " f"@ {arbiter_addr}") if self._parent_chan: try: # internal error so ship to parent without cid await self._parent_chan.send(pack_error(err)) except trio.ClosedResourceError: log.error(f"Failed to ship error to parent " f"{self._parent_chan.uid}, channel was closed") log.exception("Actor errored:") else: # XXX wait, why? # causes a hang if I always raise.. raise finally: if registered_with_arbiter: await self._do_unreg(arbiter_addr) # terminate actor once all it's peers (actors that connected # to it as clients) have disappeared if not self._no_more_peers.is_set(): if any(chan.connected() for chan in chain(*self._peers.values())): log.debug( f"Waiting for remaining peers {self._peers} to clear") await self._no_more_peers.wait() log.debug(f"All peer channels are complete") # tear down channel server no matter what since we errored # or completed self.cancel_server()
async def worker_serve( app: ASGIFramework, config: Config, *, sockets: Optional[Sockets] = None, shutdown_event: Optional[EventType] = None, task_status: trio._core._run._TaskStatus = trio.TASK_STATUS_IGNORED, ) -> None: lifespan = Lifespan(app, config) reload_ = False async with trio.open_nursery() as lifespan_nursery: await lifespan_nursery.start(lifespan.handle_lifespan) await lifespan.wait_for_startup() try: async with trio.open_nursery() as nursery: metrics_send_channel, metrics_receive_channel = trio.open_memory_channel( 100) metrics = {'total_requests': 0} async with metrics_receive_channel, metrics_send_channel: nursery.start_soon(collect_metrics, metrics_receive_channel.clone(), metrics) nursery.start_soon(log_metrics, metrics) if config.use_reloader: nursery.start_soon(observe_changes, trio.sleep) if shutdown_event is not None: nursery.start_soon(check_shutdown, shutdown_event, trio.sleep) if sockets is None: sockets = config.create_sockets() for sock in sockets.secure_sockets: sock.listen(config.backlog) for sock in sockets.insecure_sockets: sock.listen(config.backlog) ssl_context = config.create_ssl_context() listeners = [ trio.ssl.SSLListener( trio.SocketListener( trio.socket.from_stdlib_socket(sock)), ssl_context, https_compatible=True, ) for sock in sockets.secure_sockets ] listeners.extend([ trio.SocketListener( trio.socket.from_stdlib_socket(sock)) for sock in sockets.insecure_sockets ]) task_status.started() await trio.serve_listeners( partial(serve_stream, app, config, metrics_send_channel), listeners) except MustReloadException: reload_ = True except (Shutdown, KeyboardInterrupt): pass finally: await lifespan.wait_for_shutdown() lifespan_nursery.cancel_scope.cancel() if reload_: restart()