Created
January 19, 2020 22:37
-
-
Save parity3/bcd7ea933a02d5ee691a822bf0d3306a to your computer and use it in GitHub Desktop.
running quart-trio inside trio_asyncio.run
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import logging | |
import sys | |
import trio, trio_asyncio, asyncio | |
from hypercorn.trio.run import worker_serve | |
from hypercorn import Config | |
import contextlib | |
import math | |
from types import TracebackType | |
from quart import current_app, json | |
from quart.wrappers.response import DataBody | |
from quart_trio import QuartTrio | |
import triopg | |
# noinspection PyUnreachableCode | |
if 0: | |
from quart import Config as quart_Config | |
app = QuartTrio(__name__) | |
# you'll need to modify this to point to your db | |
app.config['DB_DSN'] = 'postgresql://user:@localhost/dbname' | |
@app.route('/') | |
async def index(): | |
pool = current_app.pool | |
async with pool.acquire() as conn: | |
time_from_db, = await conn.fetchrow('select CURRENT_TIMESTAMP') | |
return { 'status': 'OK', 'time_from_db': time_from_db } | |
class AfterDataBody(DataBody): | |
def __init__(self, data: bytes, do_stuff_callback: callable): | |
super().__init__(data) | |
self.do_stuff_callback = do_stuff_callback | |
async def __aexit__(self, exc_type: type, exc_value: BaseException, tb: TracebackType) -> None: | |
self.do_stuff_callback() | |
@app.route('/stop') | |
async def stop(): | |
return AfterDataBody(json.dumps({'status': 'OK'}).encode(), current_app.shutdown_event.set) | |
@app.route('/restart') | |
async def restart(): | |
current_app.retcode = 151 # this is just an arbitrary number which should tell whoever started us that | |
# we were told that we should be restarted | |
return AfterDataBody(json.dumps({'status': 'OK'}).encode(), current_app.shutdown_event.set) | |
@contextlib.asynccontextmanager | |
async def pg_pool_context(): | |
# noinspection PyProtectedMember | |
capp = current_app._get_current_object() | |
config = capp.config # type: quart_Config | |
logger = capp.logger | |
capp.pool = pool = await triopg.create_pool( | |
config['DB_DSN'], min_size=1, max_size=2, max_queries=math.inf, statement_cache_size=0).__aenter__() | |
try: | |
logger.info('asnycpg pool setup complete') | |
yield | |
finally: | |
capp.pool = None | |
await pool.close() | |
logger.info('asnycpg pool closed') | |
@app.before_serving | |
async def setup_pg_pool(): | |
# noinspection PyProtectedMember | |
capp = current_app._get_current_object() | |
capp.pool_context = pg_pool_context() | |
await capp.pool_context.__aenter__() | |
capp.logger.info('triopg pool has been set up') | |
@app.after_serving | |
async def teardown_pg_pool(): | |
# noinspection PyProtectedMember | |
capp = current_app._get_current_object() | |
pool_context = getattr(capp, 'pool_context', None) | |
if pool_context: | |
await pool_context.__aexit__(None, None, None) | |
capp.logger.info('triopg pool teardown completed') | |
async def async_run(config: Config, _app: QuartTrio): | |
# noinspection PyProtectedMember | |
asyncio._set_running_loop(asyncio.get_event_loop()) | |
_app.shutdown_event = trio.Event() | |
log = config.log | |
log.root.level = logging.INFO | |
await log.info('starting work_serve..') | |
await worker_serve(app, config, shutdown_trigger=_app.shutdown_event.wait) | |
def sync_main(): | |
# thisdir = os.path.dirname(__file__) or '.' | |
# config = Config.from_pyfile(os.path.join(thisdir,'hypercorn_config.py')) | |
# app = load_application(config.application_path) | |
config = Config() | |
trio_asyncio.run(async_run, config, app) | |
retcode = getattr(app, 'retcode', None) | |
if retcode: | |
sys.exit(retcode) | |
if __name__ == '__main__': | |
sync_main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment