File: node13.html

package info (click to toggle)
cherrypy 0.10-1
  • links: PTS
  • area: main
  • in suites: sarge
  • size: 10,324 kB
  • ctags: 1,759
  • sloc: python: 14,411; sh: 6,915; perl: 2,472; makefile: 76
file content (218 lines) | stat: -rw-r--r-- 8,746 bytes parent folder | download
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 &lt; and &gt;
        while 1:
            i=code.find('&lt;')
            if i==-1: break
            j=code.find('&gt;', i)
            if j!=-1: code=code[:i]+' '+code[j+1:]
        return code
mask:
    def index(self, code=''):
        &lt;html&gt;&lt;body&gt;
            Extracted text: &lt;py-eval="self.extractText(code)"&gt;
            &lt;form action="index"&gt;
            New text: &lt;textarea name="code"&gt;&lt;/textarea&gt;
            &lt;input type=submit&gt;
            &lt;/form&gt;
        &lt;/body&gt;&lt;/html&gt;
</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 "&lt;" but never closed with a "&gt;"), 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 "&lt;string&gt;", 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 "&lt;string&gt;", 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>