server_py3_uvloop.py 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149
  1. #!/usr/bin/env python
  2. from os import getenv
  3. from operator import itemgetter
  4. from functools import partial
  5. from random import randint
  6. import ujson as json
  7. import uvloop
  8. import asyncpg
  9. import tornado.ioloop
  10. import tornado.web
  11. import tornado.httpserver
  12. from tornado.options import options
  13. options.define('port', default=8080, type=int, help="Server port")
  14. READ_ROW_SQL = 'SELECT "randomnumber", "id" FROM "world" WHERE id = $1'
  15. WRITE_ROW_SQL = 'UPDATE "world" SET "randomnumber"=$1 WHERE id=$2'
  16. ADDITIONAL_ROW = [0, 'Additional fortune added at request time.']
  17. sort_fortunes_key = itemgetter(1)
  18. async def init_db_pool():
  19. return await asyncpg.create_pool(
  20. host="tfb-database",
  21. user="benchmarkdbuser",
  22. password="benchmarkdbpass",
  23. database="hello_world")
  24. def get_num_queries(request):
  25. try:
  26. query_count = int(request.get_query_argument('queries'))
  27. except (KeyError, IndexError, ValueError):
  28. return 1
  29. if query_count < 1:
  30. return 1
  31. if query_count > 500:
  32. return 500
  33. return query_count
  34. class JsonHandler(tornado.web.RequestHandler):
  35. def set_default_headers(self):
  36. self.set_header("Content-Type", "application/json")
  37. def write_response(self, data):
  38. self.write(json.dumps(data))
  39. class JsonHelloWorldHandler(JsonHandler):
  40. def get(self):
  41. self.write_response({"message": "Hello, World!"})
  42. class PlaintextHelloWorldHandler(tornado.web.RequestHandler):
  43. def get(self):
  44. self.set_header("Content-Type", "text/plain")
  45. self.write(b'Hello, world!')
  46. class SingleQueryHandler(JsonHandler):
  47. async def get(self):
  48. row_id = randint(1, 10000)
  49. async with self.application.pool.acquire() as connection:
  50. number = await connection.fetchval(READ_ROW_SQL, row_id)
  51. self.write_response({'id': row_id, 'randomNumber': number})
  52. class MultipleQueriesHandler(JsonHandler):
  53. async def get(self):
  54. num_queries = get_num_queries(self)
  55. row_ids = [randint(1, 10000) for _ in range(num_queries)]
  56. worlds = []
  57. async with self.application.pool.acquire() as connection:
  58. statement = await connection.prepare(READ_ROW_SQL)
  59. for row_id in row_ids:
  60. number = await statement.fetchval(row_id)
  61. worlds.append({'id': row_id, 'randomNumber': number})
  62. self.write_response(worlds)
  63. class UpdateHandler(JsonHandler):
  64. async def get(self):
  65. num_queries = get_num_queries(self)
  66. updates = [(randint(1, 10000), randint(1, 10000)) for _ in range(num_queries)]
  67. worlds = [{'id': row_id, 'randomNumber': number} for row_id, number in updates]
  68. async with self.application.pool.acquire() as connection:
  69. statement = await connection.prepare(READ_ROW_SQL)
  70. for row_id, number in updates:
  71. await statement.fetchval(row_id)
  72. await connection.executemany(WRITE_ROW_SQL, updates)
  73. self.write_response(worlds)
  74. class FortuneHandler(tornado.web.RequestHandler):
  75. async def get(self):
  76. async with self.application.pool.acquire() as connection:
  77. fortunes = await connection.fetch('SELECT * FROM Fortune')
  78. fortunes.append(ADDITIONAL_ROW)
  79. fortunes.sort(key=sort_fortunes_key)
  80. self.set_header("Content-Type", "text/html; charset=UTF-8")
  81. self.render('fortunes_asyncpg.html', fortunes=fortunes)
  82. def make_app():
  83. return tornado.web.Application([
  84. (r"/json", JsonHelloWorldHandler),
  85. (r"/plaintext", PlaintextHelloWorldHandler),
  86. (r"/db", SingleQueryHandler),
  87. (r"/queries", MultipleQueriesHandler),
  88. (r"/updates", UpdateHandler),
  89. (r"/fortunes", FortuneHandler),
  90. ],
  91. template_path="templates"
  92. )
  93. async def setup_database():
  94. return await asyncpg.create_pool(
  95. user=getenv('PGUSER', 'benchmarkdbuser'),
  96. password=getenv('PGPASS', 'benchmarkdbpass'),
  97. database='hello_world',
  98. host='tfb-database',
  99. port=5432
  100. )
  101. if __name__ == "__main__":
  102. options.parse_command_line()
  103. uvloop.install()
  104. app = make_app()
  105. server = tornado.httpserver.HTTPServer(app)
  106. server.bind(options.port)
  107. server.start(0)
  108. ioloop = tornado.ioloop.IOLoop.current()
  109. app.pool = ioloop.run_sync(partial(setup_database))
  110. ioloop.start()