1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<title>12. How to create a spinning server and then debug it</title>
<META NAME="description" CONTENT="12. How to create a spinning server and then debug it">
<META NAME="keywords" CONTENT="howto">
<META NAME="resource-type" CONTENT="document">
<META NAME="distribution" CONTENT="global">
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1">
<link rel="STYLESHEET" href="howto.css" type='text/css'>
<link rel="first" href="howto.html">
<link rel="contents" href="contents.html" title="Contents">
<LINK REL="next" HREF="node14.html">
<LINK REL="previous" HREF="node12.html">
<LINK REL="up" HREF="howto.html">
<LINK REL="next" HREF="node14.html">
<meta name='aesop' content='information'>
</head>
<body>
<DIV CLASS="navigation">
<table align="center" width="100%" cellpadding="0" cellspacing="2">
<tr>
<td><A HREF="node12.html"><img src="../icons/previous.gif"
border="0" height="32"
alt="Previous Page" width="32"></A></td>
<td><A HREF="howto.html"><img src="../icons/up.gif"
border="0" height="32"
alt="Up One Level" width="32"></A></td>
<td><A HREF="node14.html"><img src="../icons/next.gif"
border="0" height="32"
alt="Next Page" width="32"></A></td>
<td align="center" width="100%">CherryPy HowTo</td>
<td><A HREF="node1.html"><img src="../icons/contents.gif"
border="0" height="32"
alt="Contents" width="32"></A></td>
<td><img src="../icons/blank.gif"
border="0" height="32"
alt="" width="32"></td>
<td><img src="../icons/blank.gif"
border="0" height="32"
alt="" width="32"></td>
</tr></table>
<b class="navlabel">Previous:</b> <a class="sectref" HREF="node12.html">11. How to use</A>
<b class="navlabel">Up:</b> <a class="sectref" HREF="howto.html">CherryPy HowTo</A>
<b class="navlabel">Next:</b> <a class="sectref" HREF="node14.html">13. How to create</A>
<br><hr>
</DIV>
<!--End of Navigation Panel-->
<!--Table of Child-Links-->
<A NAME="CHILD_LINKS"><STRONG>Subsections</STRONG></a>
<UL CLASS="ChildLinks">
<LI><A href="node13.html#SECTION0013100000000000000000">12.1 Creating a spinning server</a>
<LI><A href="node13.html#SECTION0013200000000000000000">12.2 Debugging a spinning server</a>
</ul>
<!--End of Table of Child-Links-->
<HR>
<H1><A NAME="SECTION0013000000000000000000">
12. How to create a spinning server and then debug it</A>
</H1>
<P>
<H1><A NAME="SECTION0013100000000000000000">
12.1 Creating a spinning server</A>
</H1>
By "spinning" server, I mean a server that's stuck in a loop while trying to build a page.
<P>
The easiest way to achieve that is:
<div class="verbatim"><pre>
CherryClass Root:
view:
def index(self):
while 1: pass
</pre></div>
Compile that, start the server and try to request the home page ... :-) There you have it: a nice "spinning" server. Of course,
the page will never be rendered, and if you try to load the same page from another browser, your browser won't even be able to
connect to the CherryPy server because it's still busy trying to serve the first page (unless you have multiple server
processes running).
<P>
The way you can tell that your server is spinning is very easy: you're no longer able to connect to it, and the cpu time used
by the process (which is displayed when you do a <var>ps</var> on Unix for instance) keeps growing, meaning that the
process is not stalled, but it's actually doing something.
<P>
You might be thinking "I'm not that stupid ! I will never write such an obvious loop !".
<P>
But here is another less trivial case that actually happened to me (and that's the reason why I wrote this HowTo):
<div class="verbatim"><pre>
CherryClass Root:
function:
def extractText(self, code):
# Remove text between < and >
while 1:
i=code.find('<')
if i==-1: break
j=code.find('>', i)
if j!=-1: code=code[:i]+' '+code[j+1:]
return code
mask:
def index(self, code=''):
<html><body>
Extracted text: <py-eval="self.extractText(code)">
<form action="index">
New text: <textarea name="code"></textarea>
<input type=submit>
</form>
</body></html>
</pre></div>
The <var>extractText</var> function takes some HTML code as an input and strips out the HTML tags. The output is the text
that's extracted from the HTML code. The <var>index</var> mask just provides a textarea-based interface to test the function.
<P>
If you compile this code, run it and test it with some HTML code, it might run fine for a while, but in some cases it will
start "spinning" ! The reason is that the <var>extractText</var> function is buggy in some cases: if the code is not proper
HTML (for instance, a tag is opened with a "<" but never closed with a ">"), the function will enter an infinite loop.
Correcting that is very easy once you know what's happening (just add "else: break" after the second "if" of
the function).
<P>
But when this is happening on your production server, all you see is that your CherryPy server sometimes start spinning.
Besides, the server might run fine for days, and start spinning all the sudden, making it very hard to reproduce it
in your development environment and thus almost impossible to find out where it comes from !
<P>
The next section explain how to easily debug that to track down the culprit ...
<P>
<H1><A NAME="SECTION0013200000000000000000">
12.2 Debugging a spinning server</A>
</H1>
The following method only works on Unix because it uses the <var>gdb</var> debugger.
<P>
All you have to do is wait for your CherryPy server to start spinning. Once it happens, fire up <var>gdb</var> using the
name of the Python program that's running your CherryPy server (with the correct version). This might be for instance:
<div class="verbatim"><pre>
gdb python2.1
or
gdb python2.2
</pre></div>
Once you're in <var>gdb</var>, just attach to the CherryPy process (you can get the process number with the <var>ps</var> command):
<div class="verbatim"><pre>
attach 7457
</pre></div>
At this point, <var>gdb</var> will display a bunch of messages saying that it's reading and loading some symbols.
<P>
Now comes the clever trick: run the following command in gdb:
<div class="verbatim"><pre>
call PyRun_SimpleString("import sys, traceback; sys.stderr=open('/tmp/tb','w',0); traceback.print_stack()")
</pre></div>
<P>
This will save the traceback in the <span class="file">/tmp/tb</span> file. Just exit gdb and look at this file ... It should be obvious where
the server was stuck. In our example, the file contained the following lines:
<div class="verbatim"><pre>
File "TestServer.py", line 454, in ?
try: _serveForever(_masterSocket)
File "TestServer.py", line 215, in _serveForever
_handleRequest(_wfile)
File "TestServer.py", line 363, in _handleRequest
response.body=eval("%s.%s(%s)"%(_myClass,_function, _paramStr))
File "<string>", line 0, in ?
File "TestServer.py", line 61, in index
_page.append(str(self.extractText(code)))
File "TestServer.py", line 55, in extractText
if j!=-1: code=code[:i]+' '+code[j+1:]
File "<string>", line 1, in ?
</pre></div>
<P>
PS: Thanks to Barry Warsaw for this trick (which was originally posted to a Zope mailing list).
<P>
<DIV CLASS="navigation">
<p><hr>
<table align="center" width="100%" cellpadding="0" cellspacing="2">
<tr>
<td><A HREF="node12.html"><img src="../icons/previous.gif"
border="0" height="32"
alt="Previous Page" width="32"></A></td>
<td><A HREF="howto.html"><img src="../icons/up.gif"
border="0" height="32"
alt="Up One Level" width="32"></A></td>
<td><A HREF="node14.html"><img src="../icons/next.gif"
border="0" height="32"
alt="Next Page" width="32"></A></td>
<td align="center" width="100%">CherryPy HowTo</td>
<td><A HREF="node1.html"><img src="../icons/contents.gif"
border="0" height="32"
alt="Contents" width="32"></A></td>
<td><img src="../icons/blank.gif"
border="0" height="32"
alt="" width="32"></td>
<td><img src="../icons/blank.gif"
border="0" height="32"
alt="" width="32"></td>
</tr></table>
<b class="navlabel">Previous:</b> <a class="sectref" HREF="node12.html">11. How to use</A>
<b class="navlabel">Up:</b> <a class="sectref" HREF="howto.html">CherryPy HowTo</A>
<b class="navlabel">Next:</b> <a class="sectref" HREF="node14.html">13. How to create</A>
<hr>
<span class="release-info">Release 0.10, documentation updated on 19 March 2004.</span>
</DIV>
<!--End of Navigation Panel-->
<ADDRESS>
See <i><a href="about.html">About this document...</a></i> for information on suggesting changes.
</ADDRESS>
</BODY>
</HTML>
|