Hi,

We are running SQLAlchemy with a Multi-AZ Postgres RDS database on AWS and 
are having trouble with database connections that hangs when failover 
occurs. According to Amazon documentation for Multi-AZ RDS:

When operations such as DB Instance scaling or system upgrades like OS 
> patching are initiated for Multi-AZ deployments, for enhanced availability, 
> they are applied first on the standby prior to an automatic failover. As a 
> result, your availability impact is limited only to the time required for 
> automatic failover to complete.


and

When failing over, Amazon RDS simply flips the canonical name record 
> (CNAME) for your DB Instance to point at the standby, which is in turn 
> promoted to become the new primary. We encourage you to follow best 
> practices and implement database connection retry at the application layer.


What we are wondering is what "best practices and implement database 
connection retry" means when using SQLAlchemy? To test what happens during 
a Mutli-AZ RDS failover, we created a new Multi-AZ Postgres instance and a 
simple script that we run on a server on AWS (connecting through internal 
network to the AWS RDS instance). The script queries a few rows and insert 
a new row in a while-loop.

Running this script and then rebooting the RDS (with flag "Reboot With 
Failover?" ticked) *causes the script to hang* on session.commit(). When 
rebooting the RDS instance **without** the "Reboot With Failover?" ticked, 
the script outputs "could not connect to server: Connection refused" for a 
few seconds, and then resumes as normal.

We have tried:
 1. Using the QueuePool instead of the NullPool (we switched to NullPool 
just to isolate the error).
 2. Setting socket.setdefaulttimeout() to a low value.
 3. Passing PGOPTIONS="-c statement_timeout=1000" to make the pgdriver 
timeout.
 4. Using autocommmit=True on sessionmaker().

If we run lsof -i on the application server, we can see that the connection 
closes after each iteration in the loop. When the script hangs, we can see 
that there is one connection open which does not close, so the issue seems 
to be a missing timeout somewhere.

Do anyone know what could be causing this?

The script we run is included below.

Thanks in advance! / Jonas

import sys
from datetime import datetime
from time import time, sleep
from sqlalchemy import Column, DateTime, String, Integer, ForeignKey, 
UnicodeText, create_engine
from sqlalchemy.orm import sessionmaker
from sqlalchemy.orm.scoping import scoped_session
from sqlalchemy.pool import NullPool
from sqlalchemy.ext.declarative import declarative_base


current_milli_time = lambda: int(round(time() * 1000))
Base = declarative_base()


class Message(Base):
    __tablename__ = 'messages'
    id = Column(Integer, primary_key=True)
    body = Column(UnicodeText, nullable=False)


engine = create_engine(
'postgresql+psycopg2://local:<pw>@<aws-rds-host>/test', poolclass=NullPool)
session_factory = sessionmaker()
session_factory.configure(bind=engine)

session = scoped_session(session_factory)

while True:
  try:
    ids = ''
    start = current_milli_time()
    for msg in session.query(Message).order_by('id desc').limit(5):
      ids += str(msg.id) + ', '
    print '(%s) (took %s ms) fetched ids: %s' % (datetime.now().time().
isoformat(), current_milli_time() - start, ids)

    start = current_milli_time()
    m = Message()
    m.body = 'some text'
    session.add(m)
    session.commit()
    print '(%s) (took %s ms) inserted new message' % (datetime.now().time().
isoformat(), current_milli_time() - start))

  except Exception, e:
    print '(%s) failed due to %s' % (datetime.now().time().isoformat(), e)
    session.rollback()
  finally:
    session.remove()

  sleep(0.25)



-- 
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 [email protected].
To post to this group, send email to [email protected].
Visit this group at http://groups.google.com/group/sqlalchemy.
For more options, visit https://groups.google.com/d/optout.

Reply via email to