I am developing a CherryPy FastCGI server for lighttpd with the following setup to enable the use of SQLAlchemy ORM sessions inside CherryPy controllers. However, when I run stress tests with 14 simultaneous requests for about 500 cycles, it starts to give errors, such as AttributeError: '_ThreadData' object has no attribute 'scoped_session_class' in open_dbsession() or AttributeError: 'Request' object has no attribute 'scoped_session_class' in close_dbsession() after a while. The error rate is about 50%.
This only happens when I start the server for lighttpd, and not when it starts directly through cherrypy.engine.start() . He confirmed that connect() does not throw exceptions.
I also tried assigning the scoped_session return value to GlobalSession (like here ), but then it UnboundExceptionError errors like UnboundExceptionError and other SA level errors. (Concurrency: 10, cycles: 1000, error rate: 16%. Occurs even with a direct start.)
There are several possible reasons, but I do not have enough knowledge to select them.
1. Does the start_thread subscription start_thread in the FastCGI environment? It seems that open_dbsession() is called before connect()
2. For some reason, is cherrypy.thread_data ?
server code
import sqlalchemy as sa from sqlalchemy.orm import session_maker, scoped_session engine = sa.create_engine(dburi, strategy="threadlocal") GlobalSession = session_maker(bind=engine, transactional=False) def connect(thread_index): cherrypy.thread_data.scoped_session_class = scoped_session(GlobalSession) def open_dbsession(): cherrypy.request.scoped_session_class = cherrypy.thread_data.scoped_session_class def close_dbsession(): cherrypy.request.scoped_session_class.remove() cherrypy.tools.dbsession_open = cherrypy.Tool('on_start_resource', open_dbsession) cherrypy.tools.dbsession_close = cherrypy.Tool('on_end_resource', close_dbsession) cherrypy.engine.subscribe('start_thread', connect)
lighttpd fastcgi config
... var.server_name = "test" var.server_root = "/path/to/root" var.svc_env = "test" fastcgi.server = ( "/" => ( "cherry.fcgi" => ( "bin-path" => server_root + "/fcgi_" + server_name + ".fcgi", "bin-environment" => ( "SVC_ENV" => svc_env ), "bin-copy-environment" => ("PATH", "LC_CTYPE"), "socket" => "/tmp/cherry_" + server_name + "." + svc_env + ".sock", "check-local" => "disable", "disable-time" => 1, "min-procs" => 1, "max-procs" => 4, ), ), )
edits
- Missing
thread_index argument in sample code from source code restored (thanks to comment) - It is clarified that errors do not occur immediately.
- Narrowing conditions on lighttpd