bugdown: Spend at most 5 seconds rendering a message

(imported from commit bc092acc8b2b9f8a63af669de06c6f7512ccf8c9)
This commit is contained in:
Keegan McAllister
2013-01-29 15:47:53 -05:00
parent 14d0ec1096
commit e12f10ec1f
2 changed files with 50 additions and 1 deletions

View File

@@ -7,6 +7,7 @@ import re
from zephyr.lib.avatar import gravatar_hash from zephyr.lib.avatar import gravatar_hash
from zephyr.lib.bugdown import codehilite, fenced_code from zephyr.lib.bugdown import codehilite, fenced_code
from zephyr.lib.bugdown.fenced_code import FENCE_RE from zephyr.lib.bugdown.fenced_code import FENCE_RE
from zephyr.lib.timeout import timeout
class Gravatar(markdown.inlinepatterns.Pattern): class Gravatar(markdown.inlinepatterns.Pattern):
def handleMatch(self, match): def handleMatch(self, match):
@@ -179,7 +180,10 @@ def convert(md):
_md_engine.reset() _md_engine.reset()
try: try:
html = _md_engine.convert(md) # Spend at most 5 seconds rendering.
# Sometimes Python-Markdown is really slow; see
# https://trac.humbughq.com/ticket/345
html = timeout(5, _md_engine.convert, md)
except: except:
# FIXME: Do something more reasonable here! # FIXME: Do something more reasonable here!
html = '<p>[Humbug note: Sorry, we could not understand the formatting of your message]</p>' html = '<p>[Humbug note: Sorry, we could not understand the formatting of your message]</p>'

45
zephyr/lib/timeout.py Normal file
View File

@@ -0,0 +1,45 @@
import threading
# Based on http://code.activestate.com/recipes/483752/
class TimeoutExpired(Exception):
'''Exception raised when a function times out.'''
def __str__(self):
return 'Function call timed out.'
def timeout(timeout, func, *args, **kwargs):
'''Call the function in a separate thread.
Return its return value, or raise an exception,
within 'timeout' seconds.
The function may still be running in the background!
This may also fail to interrupt functions which are
stuck in a long-running primitive interpreter
operation.'''
class TimeoutThread(threading.Thread):
def __init__(self):
threading.Thread.__init__(self)
self.result = None
self.exn = None
# Don't block the whole program from exiting
# if this is the only thread left.
self.daemon = True
def run(self):
try:
self.result = func(*args, **kwargs)
except BaseException, e:
self.exn = e
thread = TimeoutThread()
thread.start()
thread.join(timeout)
if thread.isAlive():
raise TimeoutExpired
if thread.exn:
raise thread.exn
return thread.result