main.py 2.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091
  1. import os
  2. import multiprocessing
  3. from pathlib import Path
  4. import aiohttp_jinja2
  5. import asyncpg
  6. import jinja2
  7. from aiohttp import web
  8. from sqlalchemy.engine.url import URL
  9. from sqlalchemy.ext.asyncio import AsyncSession, create_async_engine
  10. from sqlalchemy.orm import sessionmaker
  11. from .views import (
  12. json,
  13. single_database_query_orm,
  14. multiple_database_queries_orm,
  15. fortunes,
  16. updates,
  17. plaintext,
  18. single_database_query_raw,
  19. multiple_database_queries_raw,
  20. fortunes_raw,
  21. updates_raw,
  22. )
  23. CONNECTION_ORM = os.getenv('CONNECTION', 'ORM').upper() == 'ORM'
  24. THIS_DIR = Path(__file__).parent
  25. def pg_dsn() -> str:
  26. """
  27. :return: DSN url suitable for sqlalchemy and aiopg.
  28. """
  29. return str(URL.create(
  30. database='hello_world',
  31. password=os.getenv('PGPASS', 'benchmarkdbpass'),
  32. host='tfb-database',
  33. port='5432',
  34. username=os.getenv('PGUSER', 'benchmarkdbuser'),
  35. drivername='postgresql',
  36. ))
  37. async def db_ctx(app: web.Application):
  38. dsn = pg_dsn()
  39. # number of gunicorn workers = multiprocessing.cpu_count() as per gunicorn_conf.py
  40. # max_connections = 2000 as per toolset/setup/linux/databases/postgresql/postgresql.conf:64
  41. # give 10% leeway
  42. max_size = min(1800 / multiprocessing.cpu_count(), 160)
  43. max_size = max(int(max_size), 1)
  44. min_size = max(int(max_size / 2), 1)
  45. print(f'connection pool: min size: {min_size}, max size: {max_size}, orm: {CONNECTION_ORM}')
  46. if CONNECTION_ORM:
  47. engine = create_async_engine(dsn, future=True)
  48. app['db_session'] = sessionmaker(engine, class_=AsyncSession)
  49. else:
  50. app['pg'] = await asyncpg.create_pool(dsn=dsn, min_size=min_size, max_size=max_size, loop=app.loop)
  51. yield
  52. if not CONNECTION_ORM:
  53. await app['pg'].close()
  54. def setup_routes(app):
  55. if CONNECTION_ORM:
  56. app.router.add_get('/json', json)
  57. app.router.add_get('/db', single_database_query_orm)
  58. app.router.add_get('/queries/{queries:.*}', multiple_database_queries_orm)
  59. app.router.add_get('/fortunes', fortunes)
  60. app.router.add_get('/updates/{queries:.*}', updates)
  61. app.router.add_get('/plaintext', plaintext)
  62. else:
  63. app.router.add_get('/db', single_database_query_raw)
  64. app.router.add_get('/queries/{queries:.*}', multiple_database_queries_raw)
  65. app.router.add_get('/fortunes', fortunes_raw)
  66. app.router.add_get('/updates/{queries:.*}', updates_raw)
  67. def create_app():
  68. app = web.Application()
  69. jinja2_loader = jinja2.FileSystemLoader(str(THIS_DIR / 'templates'))
  70. aiohttp_jinja2.setup(app, loader=jinja2_loader)
  71. app.cleanup_ctx.append(db_ctx)
  72. setup_routes(app)
  73. return app