app.py 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132
  1. import multiprocessing
  2. import os
  3. from random import randint, sample
  4. import asyncpg
  5. import jinja2
  6. from panther import Panther
  7. from panther.app import API
  8. from panther.request import Request
  9. from panther.response import Response, PlainTextResponse, HTMLResponse
  10. READ_ROW_SQL = 'SELECT "id", "randomnumber" FROM "world" WHERE id = $1'
  11. WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2'
  12. ADDITIONAL_ROW = [0, 'Additional fortune added at request time.']
  13. MAX_POOL_SIZE = 1000 // multiprocessing.cpu_count()
  14. MIN_POOL_SIZE = max(int(MAX_POOL_SIZE / 2), 1)
  15. pool = None
  16. async def create_db_pool():
  17. global pool
  18. pool = await asyncpg.create_pool(
  19. user='benchmarkdbuser',
  20. password='benchmarkdbpass',
  21. database='hello_world',
  22. host='tfb-database',
  23. port=5432,
  24. min_size=MIN_POOL_SIZE,
  25. max_size=MAX_POOL_SIZE,
  26. )
  27. async def clean_db_pool():
  28. await pool.close()
  29. def load_fortunes_template():
  30. path = os.path.join('templates', 'fortune.html')
  31. with open(path, 'r') as template_file:
  32. template_text = template_file.read()
  33. return jinja2.Template(template_text)
  34. fortune_template = load_fortunes_template()
  35. def get_num_queries(request):
  36. value = request.query_params.get('queries')
  37. if value is None:
  38. return 1
  39. try:
  40. query_count = int(value)
  41. except ValueError:
  42. return 1
  43. if query_count < 1:
  44. return 1
  45. if query_count > 500:
  46. return 500
  47. return query_count
  48. @API()
  49. async def json_serialization():
  50. return Response(data={'message': 'Hello, world!'})
  51. @API()
  52. async def single_database_query():
  53. row_id = randint(1, 10000)
  54. async with pool.acquire() as connection:
  55. number = await connection.fetchval(READ_ROW_SQL, row_id)
  56. return Response(data={'id': row_id, 'randomNumber': number})
  57. @API()
  58. async def multiple_database_queries(request: Request):
  59. num_queries = get_num_queries(request)
  60. row_ids = sample(range(1, 10000), num_queries)
  61. async with pool.acquire() as connection:
  62. statement = await connection.prepare(READ_ROW_SQL)
  63. worlds = [{'id': i, 'randomNumber': await statement.fetchval(i)} for i in row_ids]
  64. return Response(data=worlds)
  65. @API()
  66. async def fortunes():
  67. async with pool.acquire() as connection:
  68. fortune_records = await connection.fetch('SELECT * FROM Fortune')
  69. fortune_records.append(ADDITIONAL_ROW)
  70. fortune_records.sort(key=lambda row: row[1])
  71. data = fortune_template.render(fortunes=fortune_records)
  72. return HTMLResponse(data=data)
  73. @API()
  74. async def database_updates(request: Request):
  75. num_queries = get_num_queries(request)
  76. ids = sorted(sample(range(1, 10000 + 1), num_queries))
  77. numbers = sorted(sample(range(1, 10000), num_queries))
  78. updates = list(zip(ids, numbers))
  79. worlds = [
  80. {'id': row_id, 'randomNumber': number} for row_id, number in updates
  81. ]
  82. async with pool.acquire() as connection:
  83. statement = await connection.prepare(READ_ROW_SQL)
  84. for row_id, _ in updates:
  85. await statement.fetchval(row_id)
  86. await connection.executemany(WRITE_ROW_SQL, updates)
  87. return Response(data=worlds)
  88. @API()
  89. async def plaintext():
  90. return PlainTextResponse(b'Hello, world!')
  91. url_routing = {
  92. 'json': json_serialization,
  93. 'db': single_database_query,
  94. 'queries': multiple_database_queries,
  95. 'fortunes': fortunes,
  96. 'updates': database_updates,
  97. 'plaintext': plaintext,
  98. }
  99. app = Panther(__name__, configs=__name__, urls=url_routing, startup=create_db_pool, shutdown=clean_db_pool)