On Tuesday, May 12, 2015 at 10:06:57 AM UTC-5, Michael Bayer wrote:
>
>  
>
> On 5/12/15 9:34 AM, Jonathon Nelson wrote:
>  
> I'm working on an application where I want to use one and only one 
> connection, even in the face of errors.
> Originally I used AssertionPool, but it seemed to misbehave sometimes in 
> the face of a disconnection.
> Switching to QueuePool, I somewhat surprisingly got the same result.
>
> This is how I perform my test. Using the code below, I start it with a URI 
> and wait for it to tell me to stop postgresql, which I then do.
> I hit enter, and get an (expected) error as it fails to connect.
> When I hit enter a second time, I get an *unexpected* traceback, a 
> different one for QueuePool as for AssertionPool, but unexpected 
> nonetheless.
> If I up the pool_size to 2, everything works fine but it leaves open the 
> possibility of having more than one connection.
>
>
>
> #! /usr/bin/python
> import sys
> import sqlalchemy as sa
>
> def handle_checkout_event(dbapi_con, con_record, con_proxy):
>     try:
>         with dbapi_con.cursor() as cur:
>             cur.execute("SELECT 1")
>             cur.fetchone()
>     except Exception, e:
>         raise sa.exc.DisconnectionError()
>
> def main():
>     uri = sys.argv[1]
>     #engine = sa.create_engine(uri, poolclass=sa.pool.AssertionPool)
>     engine = sa.create_engine(uri, pool_size=1, max_overflow=0, 
> pool_timeout=0, pool_recycle=3600)
>     sa.event.listen(engine, 'checkout', handle_checkout_event)
>
>     with engine.begin() as conn:
>         pass
>     print "Now stop PG."
>     raw_input('-=>')
>
>     # should get an operational error
>     try:
>         with engine.begin() as conn:
>             pass
>         raw_input('-=>')
>     except sa.exc.OperationalError, e:
>         print >>sys.stderr, "Got an (expected) error: ", e
>
>     raw_input('-=!')
>
>     # *should* get the same thing.
>     try:
>         with engine.begin() as conn:
>             pass
>         raw_input('-=>')
>     except sa.exc.OperationalError, e:
>         print >>sys.stderr, "Got an (expected) error: ", e
>
>     print "We never get here."
>     raw_input('-=!')
>  
> your script is holding onto state that the QueuePool requires in order to 
> check the connection back in, namely the SQLAlchemy OperationalError and 
> exception context that is attached to the stack trace.
>
> Add this after the first error throw:
>
>     sys.exc_clear()
>
> now the next invocation works as expected.
>

And indeed you are correct. However, this comes as quite a surprise to me.
As an idiom:

try:
    do_stuff()
except SomeError, e:
    make_some_noise(e)
    maybe_return_here_etc

is a pretty common idiom. I tried deleting 'e' within the except block 
without any luck.
In fact, I did a search for sys.exc_clear() and found almost literally no 
code making use of that call.
I suggest that this is a bit of POLA violation (principle of least 
astonishment). Is this due to how SQLAlchemy holds on to some measure of 
state? Should it maybe be using copies or weakrefs? Or, is this more of a 
situation that only as a result of the specific configuration choices made 
above? (in which case I contend that it's still a POLA violation, but not 
one that is as likely to bite people)


-- 
You received this message because you are subscribed to the Google Groups 
"sqlalchemy" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to sqlalchemy+unsubscr...@googlegroups.com.
To post to this group, send email to sqlalchemy@googlegroups.com.
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to