app.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131
  1. import asyncio
  2. import asyncpg
  3. import os
  4. import jinja2
  5. from starlette import (
  6. asgi_application, HTMLResponse, JSONResponse, Path, PlainTextResponse, Router
  7. )
  8. from random import randint
  9. from operator import itemgetter
  10. from urllib.parse import parse_qs
  11. from ujson import dumps as ujson_dumps
  12. READ_ROW_SQL = 'SELECT "randomnumber" FROM "world" WHERE id = $1'
  13. WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2'
  14. ADDITIONAL_ROW = [0, 'Additional fortune added at request time.']
  15. class UJSONResponse(JSONResponse):
  16. def render(self, content):
  17. return ujson_dumps(content).encode('utf-8')
  18. async def setup_database():
  19. global connection_pool
  20. connection_pool = await asyncpg.create_pool(
  21. user=os.getenv('PGUSER', 'benchmarkdbuser'),
  22. password=os.getenv('PGPASS', 'benchmarkdbpass'),
  23. database='hello_world',
  24. host='tfb-database',
  25. port=5432
  26. )
  27. def load_fortunes_template():
  28. path = os.path.join('templates', 'fortune.html')
  29. with open(path, 'r') as template_file:
  30. template_text = template_file.read()
  31. return jinja2.Template(template_text)
  32. def get_num_queries(request):
  33. try:
  34. query_string = request['query_string']
  35. query_count = int(parse_qs(query_string)[b'queries'][0])
  36. except (KeyError, IndexError, ValueError):
  37. return 1
  38. if query_count < 1:
  39. return 1
  40. if query_count > 500:
  41. return 500
  42. return query_count
  43. connection_pool = None
  44. sort_fortunes_key = itemgetter(1)
  45. template = load_fortunes_template()
  46. loop = asyncio.get_event_loop()
  47. loop.run_until_complete(setup_database())
  48. @asgi_application
  49. def json_serialization(request):
  50. return UJSONResponse({'message': 'Hello, world!'})
  51. @asgi_application
  52. async def single_database_query(request):
  53. row_id = randint(1, 10000)
  54. async with connection_pool.acquire() as connection:
  55. number = await connection.fetchval(READ_ROW_SQL, row_id)
  56. return UJSONResponse({'id': row_id, 'randomNumber': number})
  57. @asgi_application
  58. async def multiple_database_queries(request):
  59. num_queries = get_num_queries(request)
  60. row_ids = [randint(1, 10000) for _ in range(num_queries)]
  61. worlds = []
  62. async with connection_pool.acquire() as connection:
  63. statement = await connection.prepare(READ_ROW_SQL)
  64. for row_id in row_ids:
  65. number = await statement.fetchval(row_id)
  66. worlds.append({'id': row_id, 'randomNumber': number})
  67. return UJSONResponse(worlds)
  68. @asgi_application
  69. async def fortunes(request):
  70. async with connection_pool.acquire() as connection:
  71. fortunes = await connection.fetch('SELECT * FROM Fortune')
  72. fortunes.append(ADDITIONAL_ROW)
  73. fortunes.sort(key=sort_fortunes_key)
  74. content = template.render(fortunes=fortunes)
  75. return HTMLResponse(content)
  76. @asgi_application
  77. async def database_updates(request):
  78. num_queries = get_num_queries(request)
  79. updates = [(randint(1, 10000), randint(1, 10000)) for _ in range(num_queries)]
  80. worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates]
  81. async with connection_pool.acquire() as connection:
  82. statement = await connection.prepare(READ_ROW_SQL)
  83. for row_id, number in updates:
  84. await statement.fetchval(row_id)
  85. await connection.executemany(WRITE_ROW_SQL, updates)
  86. return UJSONResponse(worlds)
  87. @asgi_application
  88. def plaintext(request):
  89. return PlainTextResponse(b'Hello, world!')
  90. app = Router(routes=[
  91. Path('/json', json_serialization),
  92. Path('/db', single_database_query),
  93. Path('/queries', multiple_database_queries),
  94. Path('/fortunes', fortunes),
  95. Path('/updates', database_updates),
  96. Path('/plaintext', plaintext),
  97. ])