On May 23, 7:56 pm, Michael Bayer <mike...@zzzcomputing.com> wrote:
> On May 23, 2009, at 1:47 PM, Bob Farrell wrote:
>
>
>
> > Hi, using scoped_session(sessionmaker()) to create my sessions, if I
> > hammer a
> > request (using Pylons) by repeatedly clicking on a link that uses the
> > ORM
> > somewhat extensively for the relevant request, it seems that another
> > thread is
> > getting involved with SQLAlchemy internals and pulling the rug out
> > from under
> > its feet.
>
> that means you are sharing a mapped instance between threads. A
> mapped instance, when associated with a Session (i.e. not detatched),
> should be considered as an extension of that Session's internal
> state. The Session isn't threadsafe so you can't share a persistent
> instance between threads. If you are using some kind of persistent/
> cached instances, make sure they are detatched from their original
> Session first, or merge() the instances in to the Session local to the
> request before using them (you can send the dont_load=True flag to
> merge() if you want to cut down on potentially needless SELECT
> statements).
>
Okay, thanks - I'll track down the problem with that in mind.
>
>
> > And here's how I'm dealing with creating the sessions:
>
> > threadlocal = threading.local()
>
> > Session = scoped_session(sessionmaker(autocommit=True))
> > Session.metadata = None
>
> > def setup_db():
> > if hasattr(threadlocal, 'engine'):
> > return
> > uri = config['main.engine.dburi']
> > threadlocal.engine = create_engine(uri)
> > Session.configure(bind=threadlocal.engine)
> > if Session.metadata is None:
> > Session.metadata = MetaData(threadlocal.engine)
> > model.initialise(Session.metadata)
>
> the threading.local() is unnecessary...unless you are planning for the
> same application to be run with different .ini files in each thread
> which would be extremely unusual. scoped_session() already handles
> the thread local part for you as far as Sessions are concerned, and
> Engine objects are threadsafe.
>
Ah, so "engine = create_engine(...)" will provide separate connections
as needed, rather than just a single connection ? The reason I wrote
this code was because the original code we had was causing big
problems - we were repeatedly getting "QueuePool limit of size 30
overflow 10 reached, connection timed out, timeout 30" errors, so what
I was hoping to do here was limit the connections to one per thread,
but thinking about it I suppose this code doesn't achieve that at all,
as any code can create a new connection with "engine.connect()"
I'm going to have to track down what bits of code in SQLAlchemy
implicitly create new connections so I can figure out where we're not
closing them - hopefully autocommit=True will remedy this somewhat.
Anyway, thanks a lot for the info. :-)
> Session = scoped_session(sessionmaker(autocommit=True))
> metadata = None
>
> def setup_db():
> global metadata
> if metadata is not None:
> return
> uri = config['main.engine.dburi']
> engine = create_engine(uri)
> Session.configure(bind=engine)
> metadata = MetaData(engine)
> model.initialise(metadata)
>
> if OTOH you had some reason for the threadlocal engines, then you dont
> want to use Session.configure, which configures the whole
> scoped_session(). You'd want to say
> Session(bind=my_threadlocal_engine).
--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups
"sqlalchemy" group.
To post to this group, send email to sqlalchemy@googlegroups.com
To unsubscribe from this group, send email to
sqlalchemy+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/sqlalchemy?hl=en
-~----------~----~----~----~------~----~------~--~---