@@ -49,25 +49,36 @@ def get_db_connection():
4949 conn .autocommit = True
5050 conn .set_isolation_level (ISOLATION_LEVEL_AUTOCOMMIT )
5151 yield conn
52- except DBConnectionError :
52+ except (DBConnectionError , psycopg2 .OperationalError ):
53+ db_pool = None # make sure that we reconnect next time
5354 yield None
5455 finally :
55- if db_pool is not None and conn is not None :
56+ if db_pool is not None :
5657 db_pool .putconn (conn )
5758
5859
5960@contextmanager
6061def get_db_cursor ():
6162 with get_db_connection () as connection :
6263 if connection is None :
63- yield None
64+ yield InvalidDBCursor ()
6465 return
6566
6667 cursor = connection .cursor ()
6768 try :
6869 yield cursor
6970 finally :
70- cursor .close ()
71+ if not isinstance (cursor , InvalidDBCursor ):
72+ cursor .close ()
73+
74+
75+ # In python it is not possible to throw an exception within the __enter__ phase of a with statement:
76+ # https://www.python.org/dev/peps/pep-0377/
77+ # If we want to handle DB connection failures gracefully we return a cursor which will throw
78+ # DBConnectionError exception whenever it is accessed.
79+ class InvalidDBCursor (object ):
80+ def __getattr__ (self , attr ):
81+ raise DBConnectionError ()
7182
7283
7384def db_connect ():
@@ -105,10 +116,13 @@ def db_disconnect():
105116def initial_wait_for_db ():
106117 while True :
107118 with get_db_cursor () as c :
108- if c is not None :
119+ try :
120+ c .execute ('SELECT 1;' )
121+ res = c .fetchone ()
109122 return
110- log .info ("DB connection failed - waiting for DB to become available, sleeping 5s" )
111- time .sleep (5 )
123+ except DBConnectionError :
124+ log .info ("DB connection failed - waiting for DB to become available, sleeping 5s" )
125+ time .sleep (5 )
112126
113127
114128###########################
0 commit comments