Move Markdown rendering out of the Tornado server

(imported from commit fc726939aa1061c40b292899dbbc9ade3b29ea01)
This commit is contained in:
Keegan McAllister 2012-11-13 16:12:27 -05:00
parent 9c99e00228
commit f82e8fc4d1
2 changed files with 23 additions and 3 deletions

View File

@ -379,6 +379,14 @@ class Message(models.Model):
@cache_with_key(lambda self, apply_markdown: 'message_dict:%d:%d' % (self.id, apply_markdown)) @cache_with_key(lambda self, apply_markdown: 'message_dict:%d:%d' % (self.id, apply_markdown))
def to_dict(self, apply_markdown): def to_dict(self, apply_markdown):
# Messages arrive in the Tornado process with the dicts already rendered.
# This avoids running the Markdown parser and some database queries in the single-threaded
# Tornado server.
#
# This field is not persisted to the database and will disappear if the object is re-fetched.
if hasattr(self, 'precomputed_dicts'):
return self.precomputed_dicts['text/html' if apply_markdown else 'text/x-markdown']
obj = dict( obj = dict(
id = self.id, id = self.id,
sender_email = self.sender.user.email, sender_email = self.sender.user.email,
@ -481,10 +489,15 @@ def do_send_message(message, no_log=False):
# We can only publish messages to longpolling clients if the Tornado server is running. # We can only publish messages to longpolling clients if the Tornado server is running.
if settings.TORNADO_SERVER: if settings.TORNADO_SERVER:
# Render Markdown etc. here, so that the single-threaded Tornado server doesn't have to.
# TODO: Reduce duplication in what we send.
rendered = { 'text/html': message.to_dict(apply_markdown=True),
'text/x-markdown': message.to_dict(apply_markdown=False) }
requests.post(settings.TORNADO_SERVER + '/notify_new_message', data=[ requests.post(settings.TORNADO_SERVER + '/notify_new_message', data=[
('secret', settings.SHARED_SECRET), ('secret', settings.SHARED_SECRET),
('message', message.id), ('message', message.id),
('users', ','.join(str(user.id) for user in recipients))]) ('rendered', simplejson.dumps(rendered)),
('users', ','.join(str(user.id) for user in recipients))])
class Subscription(models.Model): class Subscription(models.Model):
user_profile = models.ForeignKey(UserProfile) user_profile = models.ForeignKey(UserProfile)

View File

@ -647,6 +647,13 @@ def notify_new_message(request):
for user in request.POST['users'].split(',')] for user in request.POST['users'].split(',')]
message = Message.objects.get(id=request.POST['message']) message = Message.objects.get(id=request.POST['message'])
# Cause message.to_dict() to return the dicts already rendered in the other process.
#
# We decode this JSON only to eventually re-encode it as JSON.
# This isn't trivial to fix, because we do access some fields in the meantime
# (see send_with_safety_check). It's probably not a big deal.
message.precomputed_dicts = simplejson.loads(request.POST['rendered'])
for user in users: for user in users:
user.receive(message) user.receive(message)