Skip to content

Commit 6d311a3

Browse files
authored
Ensure recorder event loop recovers if the database server dis… (home-assistant#33253)
If the database server disconnects there were exceptions that were not trapped which would cause the recorder event loop to collapse. As we never want the loop to end we trap exceptions broadly. Fix a bug in the new commit interval setting which caused it to always commit after 1s
1 parent 4bbc0a0 commit 6d311a3

File tree

1 file changed

+33
-14
lines changed

1 file changed

+33
-14
lines changed

homeassistant/components/recorder/__init__.py

+33-14
Original file line numberDiff line numberDiff line change
@@ -342,7 +342,6 @@ def async_purge(now):
342342
# has changed. This reduces the disk io.
343343
while True:
344344
event = self.queue.get()
345-
346345
if event is None:
347346
self._close_run()
348347
self._close_connection()
@@ -356,7 +355,7 @@ def async_purge(now):
356355
self.queue.task_done()
357356
if self.commit_interval:
358357
self._timechanges_seen += 1
359-
if self.commit_interval >= self._timechanges_seen:
358+
if self._timechanges_seen >= self.commit_interval:
360359
self._timechanges_seen = 0
361360
self._commit_event_session_or_retry()
362361
continue
@@ -376,6 +375,9 @@ def async_purge(now):
376375
self.event_session.flush()
377376
except (TypeError, ValueError):
378377
_LOGGER.warning("Event is not JSON serializable: %s", event)
378+
except Exception as err: # pylint: disable=broad-except
379+
# Must catch the exception to prevent the loop from collapsing
380+
_LOGGER.exception("Error adding event: %s", err)
379381

380382
if dbevent and event.event_type == EVENT_STATE_CHANGED:
381383
try:
@@ -387,6 +389,9 @@ def async_purge(now):
387389
"State is not JSON serializable: %s",
388390
event.data.get("new_state"),
389391
)
392+
except Exception as err: # pylint: disable=broad-except
393+
# Must catch the exception to prevent the loop from collapsing
394+
_LOGGER.exception("Error adding state change: %s", err)
390395

391396
# If they do not have a commit interval
392397
# than we commit right away
@@ -404,17 +409,26 @@ def _commit_event_session_or_retry(self):
404409
try:
405410
self._commit_event_session()
406411
return
407-
408-
except exc.OperationalError as err:
409-
_LOGGER.error(
410-
"Error in database connectivity: %s. " "(retrying in %s seconds)",
411-
err,
412-
self.db_retry_wait,
413-
)
412+
except (exc.InternalError, exc.OperationalError) as err:
413+
if err.connection_invalidated:
414+
_LOGGER.error(
415+
"Database connection invalidated: %s. "
416+
"(retrying in %s seconds)",
417+
err,
418+
self.db_retry_wait,
419+
)
420+
else:
421+
_LOGGER.error(
422+
"Error in database connectivity: %s. "
423+
"(retrying in %s seconds)",
424+
err,
425+
self.db_retry_wait,
426+
)
414427
tries += 1
415428

416-
except exc.SQLAlchemyError:
417-
_LOGGER.exception("Error saving events")
429+
except Exception as err: # pylint: disable=broad-except
430+
# Must catch the exception to prevent the loop from collapsing
431+
_LOGGER.exception("Error saving events: %s", err)
418432
return
419433

420434
_LOGGER.error(
@@ -423,10 +437,15 @@ def _commit_event_session_or_retry(self):
423437
)
424438
try:
425439
self.event_session.close()
426-
except exc.SQLAlchemyError:
427-
_LOGGER.exception("Failed to close event session.")
440+
except Exception as err: # pylint: disable=broad-except
441+
# Must catch the exception to prevent the loop from collapsing
442+
_LOGGER.exception("Error while closing event session: %s", err)
428443

429-
self.event_session = self.get_session()
444+
try:
445+
self.event_session = self.get_session()
446+
except Exception as err: # pylint: disable=broad-except
447+
# Must catch the exception to prevent the loop from collapsing
448+
_LOGGER.exception("Error while creating new event session: %s", err)
430449

431450
def _commit_event_session(self):
432451
try:

0 commit comments

Comments
 (0)