Skip to content

Instantly share code, notes, and snippets.

@parity3
Created January 19, 2020 22:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save parity3/bcd7ea933a02d5ee691a822bf0d3306a to your computer and use it in GitHub Desktop.
Save parity3/bcd7ea933a02d5ee691a822bf0d3306a to your computer and use it in GitHub Desktop.
running quart-trio inside trio_asyncio.run
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