Changeset 1231
- Timestamp:
- 08/09/06 18:50:46
- Files:
-
- trunk/cherrypy/__init__.py (modified) (1 diff)
- trunk/cherrypy/_cpengine.py (modified) (5 diffs)
- trunk/cherrypy/_cperror.py (modified) (1 diff)
- trunk/cherrypy/_cprequest.py (modified) (8 diffs)
- trunk/cherrypy/test/test_states.py (modified) (3 diffs)
- trunk/cherrypy/test/test_states_demo.py (modified) (1 diff)
Legend:
- Unmodified
- Added
- Removed
- Modified
- Copied
- Moved
trunk/cherrypy/__init__.py
r1225 r1231 5 5 import logging as _logging 6 6 7 from _cperror import HTTPError, HTTPRedirect, InternalRedirect, NotFound, WrongConfigValue 7 from _cperror import HTTPError, HTTPRedirect, InternalRedirect, NotFound 8 from _cperror import WrongConfigValue, TimeoutError 8 9 import config 9 10 trunk/cherrypy/_cpengine.py
r1227 r1231 56 56 self.seen_threads = {} 57 57 58 self.servings = [] 59 58 60 self.mtimes = {} 59 61 self.reload_files = [] … … 71 73 for func in self.on_start_engine_list: 72 74 func() 75 73 76 self.state = STARTED 77 78 freq = float(cherrypy.config.get('deadlock_poll_freq', 60)) 79 if freq > 0: 80 self.monitor_thread = threading.Timer(freq, self.monitor) 81 self.monitor_thread.start() 82 74 83 if blocking: 75 84 self.block() … … 157 166 func() 158 167 168 if self.monitor_thread: 169 self.monitor_thread.cancel() 170 self.monitor_thread = None 171 159 172 self.state = STOPPED 160 173 cherrypy.log("CherryPy shut down", "ENGINE") … … 183 196 """ 184 197 if self.state == STOPPED: 185 r = NotReadyRequest("The CherryPy engine has stopped.")198 req = NotReadyRequest("The CherryPy engine has stopped.") 186 199 elif self.state == STARTING: 187 r = NotReadyRequest("The CherryPy engine could not start.")200 req = NotReadyRequest("The CherryPy engine could not start.") 188 201 else: 189 202 # Only run on_start_thread_list if the engine is running. … … 195 208 for func in self.on_start_thread_list: 196 209 func(i) 197 r = self.request_class(local_host, remote_host, scheme) 198 cherrypy.serving.request = r 199 cherrypy.serving.response = self.response_class() 200 return r 210 req = self.request_class(local_host, remote_host, scheme) 211 cherrypy.serving.request = req 212 cherrypy.serving.response = resp = self.response_class() 213 self.servings.append((req, resp)) 214 return req 215 216 def monitor(self): 217 """Check timeout on all responses.""" 218 if self.state == STARTED: 219 for req, resp in self.servings: 220 resp.check_timeout() 221 freq = float(cherrypy.config.get('deadlock_poll_freq', 60)) 222 self.monitor_thread = threading.Timer(freq, self.monitor) 223 self.monitor_thread.start() 201 224 202 225 def start_with_callback(self, func, args=None, kwargs=None): trunk/cherrypy/_cperror.py
r1229 r1231 201 201 path = cherrypy.request.path 202 202 self.args = (path,) 203 HTTPError.__init__(self, 404, "The path %s was not found." % repr(path)) 203 HTTPError.__init__(self, 404, "The path %r was not found." % path) 204 205 206 class TimeoutError(Exception): 207 """Exception raised when Response.timed_out is detected.""" 208 pass 204 209 205 210 trunk/cherrypy/_cprequest.py
r1229 r1231 31 31 def run(self, point): 32 32 """Execute all registered callbacks for the given point.""" 33 if cherrypy.response.timed_out: 34 raise cherrypy.TimeoutError() 35 33 36 failsafe = point in self.failsafe 34 37 for callback in self.callbacks[point]: … … 108 111 self.closed = True 109 112 self.hooks.run('on_end_request') 113 114 s = (self, cherrypy.serving.response) 115 try: 116 cherrypy.engine.servings.remove(s) 117 except ValueError: 118 pass 119 110 120 cherrypy.serving.__dict__.clear() 111 121 … … 180 190 except (KeyboardInterrupt, SystemExit): 181 191 raise 192 except cherrypy.TimeoutError: 193 raise 182 194 except: 183 195 if cherrypy.config.get("throw_errors", False): … … 199 211 try: 200 212 try: 213 if cherrypy.response.timed_out: 214 raise cherrypy.TimeoutError() 215 201 216 self.hooks = HookMap(self.hookpoints) 202 217 self.hooks.failsafe = ['on_start_resource', 'on_end_resource', … … 595 610 596 611 def __set__(self, obj, value): 612 if cherrypy.response.timed_out: 613 raise cherrypy.TimeoutError() 597 614 # Convert the given value to an iterable object. 598 615 if isinstance(value, types.FileType): … … 624 641 625 642 # Class attributes for dev-time introspection. 626 status = None627 header_list = None643 status = "" 644 header_list = [] 628 645 headers = http.HeaderMap() 629 646 simple_cookie = Cookie.SimpleCookie() 630 647 body = Body() 648 time = None 649 timed_out = False 631 650 632 651 def __init__(self): 633 652 self.status = None 634 653 self.header_list = None 635 self. body = None654 self._body = [] 636 655 self.time = time.time() 637 656 … … 653 672 def finalize(self): 654 673 """Transform headers (and cookies) into cherrypy.response.header_list.""" 674 if self.timed_out: 675 raise cherrypy.TimeoutError() 655 676 656 677 try: … … 686 707 name, value = line.split(": ", 1) 687 708 h.append((name, value)) 709 710 def check_timeout(self): 711 """If now > self.time + deadlock_timeout, set self.timed_out. 712 713 This purposefully sets a flag, rather than raising an error, 714 so that a monitor thread can interrupt the Response thread. 715 """ 716 timeout = float(cherrypy.config.get('deadlock_timeout', 300)) 717 if time.time() > self.time + timeout: 718 self.timed_out = True 719 trunk/cherrypy/test/test_states.py
r1228 r1231 23 23 return "app was restarted succesfully" 24 24 restart.exposed = True 25 26 def block_explicit(self): 27 while True: 28 if cherrypy.response.timed_out: 29 cherrypy.response.timed_out = False 30 return "broken!" 31 time.sleep(0.1) 32 block_explicit.exposed = True 33 34 def block_implicit(self): 35 raise cherrypy.InternalRedirect("/block_implicit") 36 block_implicit.exposed = True 37 block_implicit._cp_config = {'recursive_redirect': True} 25 38 26 39 cherrypy.tree.mount(Root()) … … 28 41 'log_to_screen': False, 29 42 'environment': 'production', 43 'deadlock_poll_freq': 1, 44 'deadlock_timeout': 2, 30 45 }) 31 46 … … 183 198 self.assertEqual(len(db_connection.threads), 0) 184 199 185 def test_3_Autoreload(self): 200 def test_3_Deadlocks(self): 201 cherrypy.engine.start(blocking=False) 202 cherrypy.server.start() 203 try: 204 self.assertNotEqual(cherrypy.engine.monitor_thread, None) 205 206 # Request a "normal" page. 207 self.assertEqual(cherrypy.engine.servings, []) 208 self.getPage("/") 209 self.assertBody("Hello World") 210 # request.close is called async. 211 while cherrypy.engine.servings: 212 time.sleep(0.1) 213 214 # Request a page that explicitly checks itself for deadlock. 215 # The deadlock_timeout should be 2 secs. 216 self.getPage("/block_explicit") 217 self.assertBody("broken!") 218 219 # Request a page that implicitly breaks deadlock. 220 # If we deadlock, we want to touch as little code as possible, 221 # so we won't even call handle_error, just bail ASAP. 222 self.getPage("/block_implicit") 223 self.assertStatus(500) 224 self.assertInBody("raise cherrypy.TimeoutError()") 225 finally: 226 cherrypy.engine.stop() 227 cherrypy.server.stop() 228 229 def test_4_Autoreload(self): 186 230 if self.server_class: 187 231 demoscript = os.path.join(os.getcwd(), os.path.dirname(__file__), trunk/cherrypy/test/test_states_demo.py
r1219 r1231 28 28 }) 29 29 cherrypy.quickstart(Root()) 30 30

