app.py 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209
  1. #!/usr/bin/env python
  2. from functools import partial
  3. import json
  4. from operator import attrgetter
  5. import os
  6. from random import randint
  7. import sys
  8. from email.utils import formatdate
  9. import flask
  10. from flask import Flask, request, render_template, make_response, jsonify
  11. from flask_sqlalchemy import SQLAlchemy
  12. from sqlalchemy import create_engine
  13. from sqlalchemy.ext import baked
  14. if sys.version_info[0] == 3:
  15. xrange = range
  16. _is_pypy = hasattr(sys, 'pypy_version_info')
  17. DBDRIVER = 'mysql+pymysql' if _is_pypy else 'mysql' # mysqlclient is slow on PyPy
  18. DBHOST = 'tfb-database'
  19. # setup
  20. app = Flask(__name__)
  21. app.config['SQLALCHEMY_DATABASE_URI'] = DBDRIVER + '://benchmarkdbuser:benchmarkdbpass@%s:3306/hello_world?charset=utf8' % DBHOST
  22. app.config['SQLALCHEMY_TRACK_MODIFICATIONS'] = False
  23. app.config['JSONIFY_PRETTYPRINT_REGULAR'] = False
  24. db = SQLAlchemy(app)
  25. dbraw_engine = create_engine(app.config['SQLALCHEMY_DATABASE_URI'], connect_args={'autocommit': True}, pool_reset_on_return=None)
  26. bakery = baked.bakery()
  27. # models
  28. class World(db.Model):
  29. __tablename__ = "world"
  30. id = db.Column(db.Integer, primary_key=True)
  31. randomNumber = db.Column(db.Integer)
  32. # http://stackoverflow.com/questions/7102754/jsonify-a-sqlalchemy-result-set-in-flask
  33. @property
  34. def serialize(self):
  35. """Return object data in easily serializeable format"""
  36. return {
  37. 'id' : self.id,
  38. 'randomNumber': self.randomNumber
  39. }
  40. @staticmethod
  41. def get(ident):
  42. baked_query = bakery(lambda s: s.query(World))
  43. return baked_query(db.session()).get(ident)
  44. class Fortune(db.Model):
  45. __tablename__ = "fortune"
  46. id = db.Column(db.Integer, primary_key=True)
  47. message = db.Column(db.String)
  48. # views
  49. # flask.jsonify doesn't allow array at top level for security concern.
  50. # So we should have oriiginal one.
  51. def json_response(obj):
  52. res = make_response(json.dumps(obj))
  53. res.mimetype = "application/json"
  54. return add_date_header(res)
  55. def add_date_header(res):
  56. res.headers['Date'] = formatdate(timeval=None, localtime=False, usegmt=True)
  57. return res
  58. @app.route("/json")
  59. def hello():
  60. return add_date_header(jsonify(message='Hello, World!'))
  61. @app.route("/db")
  62. def get_random_world():
  63. num_queries = request.args.get("queries", 1, type=int)
  64. if num_queries < 1:
  65. num_queries = 1
  66. if num_queries > 500:
  67. num_queries = 500
  68. worlds = [World.get(randint(1, 10000)).serialize
  69. for _ in xrange(num_queries)]
  70. return json_response(worlds)
  71. @app.route("/dbs")
  72. def get_random_world_single():
  73. wid = randint(1, 10000)
  74. worlds = World.get(wid).serialize
  75. return json_response(worlds)
  76. @app.route("/dbraw")
  77. def get_random_world_raw():
  78. connection = dbraw_engine.connect()
  79. num_queries = request.args.get("queries", 1, type=int)
  80. if num_queries < 1:
  81. num_queries = 1
  82. if num_queries > 500:
  83. num_queries = 500
  84. worlds = []
  85. for i in xrange(num_queries):
  86. wid = randint(1, 10000)
  87. result = connection.execute("SELECT * FROM world WHERE id = " + str(wid)).fetchone()
  88. worlds.append({'id': result[0], 'randomNumber': result[1]})
  89. connection.close()
  90. return json_response(worlds)
  91. @app.route("/dbsraw")
  92. def get_random_world_single_raw():
  93. connection = dbraw_engine.connect()
  94. wid = randint(1, 10000)
  95. result = connection.execute("SELECT * FROM world WHERE id = " + str(wid)).fetchone()
  96. worlds = {'id': result[0], 'randomNumber': result[1]}
  97. connection.close()
  98. return json_response(worlds)
  99. @app.route("/fortunes")
  100. def get_fortunes():
  101. fortunes = list(Fortune.query.all())
  102. fortunes.append(Fortune(id=0, message="Additional fortune added at request time."))
  103. fortunes.sort(key=attrgetter('message'))
  104. return add_date_header(make_response(render_template('fortunes.html', fortunes=fortunes)))
  105. @app.route("/fortunesraw")
  106. def get_fortunes_raw():
  107. res = dbraw_engine.execute("SELECT * FROM fortune")
  108. fortunes = res.fetchall()
  109. res.close()
  110. fortunes.append(Fortune(id=0, message="Additional fortune added at request time."))
  111. fortunes.sort(key=attrgetter('message'))
  112. return add_date_header(make_response(render_template('fortunes.html', fortunes=fortunes)))
  113. @app.route("/updates")
  114. def updates():
  115. """Test 5: Database Updates"""
  116. num_queries = request.args.get('queries', 1, type=int)
  117. if num_queries < 1:
  118. num_queries = 1
  119. if num_queries > 500:
  120. num_queries = 500
  121. worlds = []
  122. rp = partial(randint, 1, 10000)
  123. ids = [rp() for _ in xrange(num_queries)]
  124. ids.sort() # To avoid deadlock
  125. for id in ids:
  126. world = World.get(id)
  127. world.randomNumber = rp()
  128. worlds.append(world.serialize)
  129. res = json_response(worlds)
  130. db.session.commit()
  131. return res
  132. @app.route("/raw-updates")
  133. def raw_updates():
  134. """Test 5: Database Updates"""
  135. connection = dbraw_engine.connect()
  136. try:
  137. num_queries = request.args.get('queries', 1, type=int)
  138. if num_queries < 1:
  139. num_queries = 1
  140. if num_queries > 500:
  141. num_queries = 500
  142. worlds = []
  143. rp = partial(randint, 1, 10000)
  144. for i in xrange(num_queries):
  145. world = connection.execute("SELECT * FROM world WHERE id=%s", (rp(),)).fetchone()
  146. randomNumber = rp()
  147. worlds.append({'id': world['id'], 'randomNumber': randomNumber})
  148. connection.execute("UPDATE World SET randomNumber=%s WHERE id=%s", (randomNumber, world['id']))
  149. return json_response(worlds)
  150. finally:
  151. connection.close()
  152. @app.route('/plaintext')
  153. def plaintext():
  154. """Test 6: Plaintext"""
  155. response = make_response(b'Hello, World!')
  156. response.content_type = 'text/plain'
  157. return add_date_header(response)
  158. try:
  159. import meinheld
  160. meinheld.server.set_access_logger(None)
  161. meinheld.set_keepalive(120)
  162. except ImportError:
  163. pass
  164. # entry point for debugging
  165. if __name__ == "__main__":
  166. app.run(debug=True)