Skip to content

Commit 5ce6c8d

Browse files
author
Anze
committed
Nicer DB connection loss handling (InvalidDBCursor)
1 parent 348d8cf commit 5ce6c8d

File tree

2 files changed

+21
-11
lines changed

2 files changed

+21
-11
lines changed

dbutils.py

Lines changed: 21 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -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
6061
def 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

7384
def db_connect():
@@ -105,10 +116,13 @@ def db_disconnect():
105116
def 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
###########################

snmpbot.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -40,8 +40,6 @@ class InvalidOutputPath(Exception):
4040

4141
def _get_previous_counter_value(counter_ident):
4242
with get_db_cursor() as c:
43-
if c is None:
44-
raise DBConnectionError()
4543
try:
4644
c.execute(f'SELECT value, ts FROM {DB_PREFIX}bot_counters WHERE id = %s;', (counter_ident,))
4745
rec = c.fetchone()
@@ -56,8 +54,6 @@ def _get_previous_counter_value(counter_ident):
5654

5755
def _save_current_counter_value(new_value, now, counter_ident):
5856
with get_db_cursor() as c:
59-
if c is None:
60-
raise DBConnectionError()
6157
c.execute(f"INSERT INTO {DB_PREFIX}bot_counters (id, value, ts) VALUES (%s, %s, %s) ON CONFLICT (id) DO UPDATE SET value = %s, ts = %s;",
6258
(counter_ident, new_value, now, new_value, now))
6359

0 commit comments

Comments
 (0)