Thanks this is very helpful and I will try reproduce it. Are you running the trunk version or which other version?
Massimo On Jan 19, 12:45 pm, VP <[email protected]> wrote: > UPDATE: I am able to reproduce this "Premature end of script headers: > wsgihandler.py" error with a slightly modified app based on the image > blog in the web2py book. I modified it so that images are shown in > the index page, instead of having just the titles listed. > > Testing using: ab -kc 100 -t 20https://domain.com/imageblog/default/index/ > > If I am simply doing this, there's no error. BUT when I was running > this test, while simultaneously browsing the website, clicking on > images, etc., then the error appeared, consistently. > > Monitoring available RAM while running this test showed system RAM > peeked at about 500MB, still a few hundreds MB available. This is on > the same server as the other app. VPS. 768MB RAM. 1GB RAM > Burstable. About 129 apache2 processes running and 11,000 files > openning. > > sudo ps aux | grep apache2 | wc > 129 1675 11847 > > sudo lsof | wc > 10982 106870 1313126 > > ================================================= > Here's a typical Apache Bench result: > > Server Software: Apache/2.2.9 > Server Port: 443 > SSL/TLS Protocol: TLSv1/SSLv3,DHE-RSA-AES256-SHA,1024,256 > > Document Path: /imageblog/default/index/ > Document Length: 13130 bytes > > Concurrency Level: 100 > Time taken for tests: 20.004 seconds > Complete requests: 588 > Failed requests: 15 > (Connect: 0, Receive: 0, Length: 15, Exceptions: 0) > Write errors: 0 > Non-2xx responses: 15 > Keep-Alive requests: 573 > Total transferred: 7875930 bytes > HTML transferred: 7564607 bytes > Requests per second: 29.39 [#/sec] (mean) > Time per request: 3401.991 [ms] (mean) > Time per request: 34.020 [ms] (mean, across all concurrent > requests) > Transfer rate: 384.50 [Kbytes/sec] received > > Connection Times (ms) > min mean[+/-sd] median max > Connect: 0 912 2146.5 0 7265 > Processing: 86 2234 1303.3 2781 4427 > Waiting: 85 2136 1281.0 2759 4316 > Total: 86 3146 2410.6 3017 10478 > > Percentage of the requests served within a certain time (ms) > 50% 3017 > 66% 3222 > 75% 3939 > 80% 4029 > 90% 7089 > 95% 9409 > 98% 10098 > 99% 10223 > 100% 10478 (longest request) > > ================================================= > > Relevant excerpt of db.py: > > db = DAL('postgres://username:password@localhost:5432/imageblog', > pool_size=20) > > ================================================= > Model: > > db.define_table('image', > Field('title'), > Field('file', 'upload')) > > db.define_table('comment', > Field('image_id', db.image), > Field('author'), > Field('email'), > Field('body', 'text')) > > db.image.title.requires = IS_NOT_IN_DB(db, db.image.title) > db.comment.image_id.requires = IS_IN_DB(db, db.image.id, '%(title)s') > db.comment.author.requires = IS_NOT_EMPTY() > db.comment.email.requires = IS_EMAIL() > db.comment.body.requires = IS_NOT_EMPTY() > > ================================================= > Controller: > > def index(): > images = db().select(db.image.ALL, orderby=db.image.title) > return dict(images=images) > > @auth.requires_login() > def add(): > form = crud.create(db.image, next = URL('index')) > return dict(form=form) > > def show(): > image = db(db.image.id==request.args(0)).select().first() > form = SQLFORM(db.comment) > form.vars.image_id = image.id > if form.accepts(request.vars, session): > response.flash = 'your comment is posted' > comments = db(db.comment.image_id==image.id).select() > return dict(image=image, comments=comments, form=form) > > def user(): > """ > exposes: > http://..../[app]/default/user/login > http://..../[app]/default/user/logout > http://..../[app]/default/user/register > http://..../[app]/default/user/profile > http://..../[app]/default/user/retrieve_password > http://..../[app]/default/user/change_password > use @auth.requires_login() > @auth.requires_membership('group name') > @auth.requires_permission('read','table name',record_id) > to decorate functions that need access control > """ > return dict(form=auth()) > > def download(): > """ > allows downloading of uploaded files > http://..../[app]/default/download/[filename] > """ > return response.download(request,db) > > def call(): > """ > exposes services. for example: > http://..../[app]/default/call/jsonrpc > decorate with @services.jsonrpc the functions to expose > supports xml, json, xmlrpc, jsonrpc, amfrpc, rss, csv > """ > session.forget() > return service() > > ================================================= > View (index.html) > > {{extend 'layout.html'}} > <h1>Current Images</h1> > > {{for image in images:}} > <div class="entry" style="padding:1em; border-bottom:1px dashed > #999;"> > <div class="entrytitle" style="font-size:150%;">{{=A(image.title, > _href=URL("show", args=image.id))}}</div> > <div class="entryimage"><img src="{{=URL('download', > args=image.file)}}"></div> > </div> > > {{pass}} > > ================================================= > > Apache's site-enabled/000-default: > > <VirtualHost *:80> > WSGIDaemonProcess web2py user=username group=username \ > display-name=%{GROUP} > WSGIProcessGroup web2py > WSGIScriptAlias / /home/username/web2py/wsgihandler.py > > Alias /awstats-icon/ /usr/share/awstats/icon/ > <Directory /usr/share/awstats/icon> > Options None > AllowOverride None > Order allow,deny > Allow from all > </Directory> > > <Directory /home/username/web2py> > AllowOverride None > Order Allow,Deny > Deny from all > <Files wsgihandler.py> > Allow from all > </Files> > </Directory> > > AliasMatch ^/([^/]+)/static/(.*) \ > /home/username/web2py/applications/$1/static/$2 > > <Directory /home/username/web2py/applications/*/static/> > Options -Indexes > Order Allow,Deny > Allow from all > </Directory> > > <Location /admin> > Deny from all > </Location> > > <LocationMatch ^/([^/]+)/appadmin> > Deny from all > </LocationMatch> > > CustomLog /var/log/apache2/access.log common > ErrorLog /var/log/apache2/error.log > </VirtualHost>

