mirror of
https://github.com/home-assistant/core.git
synced 2025-07-15 09:17:10 +00:00
Ensure recorder runs are cleaned up during purge (#36989)
Co-authored-by: Paulus Schoutsen <balloob@gmail.com>
This commit is contained in:
parent
b4489e132c
commit
ad6315be5c
@ -6,7 +6,7 @@ from sqlalchemy.exc import SQLAlchemyError
|
|||||||
|
|
||||||
import homeassistant.util.dt as dt_util
|
import homeassistant.util.dt as dt_util
|
||||||
|
|
||||||
from .models import Events, States
|
from .models import Events, RecorderRuns, States
|
||||||
from .util import session_scope
|
from .util import session_scope
|
||||||
|
|
||||||
_LOGGER = logging.getLogger(__name__)
|
_LOGGER = logging.getLogger(__name__)
|
||||||
@ -33,6 +33,13 @@ def purge_old_data(instance, purge_days, repack):
|
|||||||
)
|
)
|
||||||
_LOGGER.debug("Deleted %s events", deleted_rows)
|
_LOGGER.debug("Deleted %s events", deleted_rows)
|
||||||
|
|
||||||
|
deleted_rows = (
|
||||||
|
session.query(RecorderRuns)
|
||||||
|
.filter(RecorderRuns.start < purge_before)
|
||||||
|
.delete(synchronize_session=False)
|
||||||
|
)
|
||||||
|
_LOGGER.debug("Deleted %s recorder_runs", deleted_rows)
|
||||||
|
|
||||||
if repack:
|
if repack:
|
||||||
# Execute sqlite or postgresql vacuum command to free up space on disk
|
# Execute sqlite or postgresql vacuum command to free up space on disk
|
||||||
if instance.engine.driver in ("pysqlite", "postgresql"):
|
if instance.engine.driver in ("pysqlite", "postgresql"):
|
||||||
@ -41,7 +48,7 @@ def purge_old_data(instance, purge_days, repack):
|
|||||||
# Optimize mysql / mariadb tables to free up space on disk
|
# Optimize mysql / mariadb tables to free up space on disk
|
||||||
elif instance.engine.driver == "mysqldb":
|
elif instance.engine.driver == "mysqldb":
|
||||||
_LOGGER.debug("Optimizing SQL DB to free space")
|
_LOGGER.debug("Optimizing SQL DB to free space")
|
||||||
instance.engine.execute("OPTIMIZE TABLE states, events")
|
instance.engine.execute("OPTIMIZE TABLE states, events, recorder_runs")
|
||||||
|
|
||||||
except SQLAlchemyError as err:
|
except SQLAlchemyError as err:
|
||||||
_LOGGER.warning("Error purging history: %s.", err)
|
_LOGGER.warning("Error purging history: %s.", err)
|
||||||
|
@ -5,9 +5,10 @@ import unittest
|
|||||||
|
|
||||||
from homeassistant.components import recorder
|
from homeassistant.components import recorder
|
||||||
from homeassistant.components.recorder.const import DATA_INSTANCE
|
from homeassistant.components.recorder.const import DATA_INSTANCE
|
||||||
from homeassistant.components.recorder.models import Events, States
|
from homeassistant.components.recorder.models import Events, RecorderRuns, States
|
||||||
from homeassistant.components.recorder.purge import purge_old_data
|
from homeassistant.components.recorder.purge import purge_old_data
|
||||||
from homeassistant.components.recorder.util import session_scope
|
from homeassistant.components.recorder.util import session_scope
|
||||||
|
from homeassistant.util import dt as dt_util
|
||||||
|
|
||||||
from tests.async_mock import patch
|
from tests.async_mock import patch
|
||||||
from tests.common import get_test_home_assistant, init_recorder_component
|
from tests.common import get_test_home_assistant, init_recorder_component
|
||||||
@ -94,6 +95,32 @@ class TestRecorderPurge(unittest.TestCase):
|
|||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
def _add_test_recorder_runs(self):
|
||||||
|
"""Add a few recorder_runs for testing."""
|
||||||
|
now = datetime.now()
|
||||||
|
five_days_ago = now - timedelta(days=5)
|
||||||
|
eleven_days_ago = now - timedelta(days=11)
|
||||||
|
|
||||||
|
self.hass.block_till_done()
|
||||||
|
self.hass.data[DATA_INSTANCE].block_till_done()
|
||||||
|
|
||||||
|
with recorder.session_scope(hass=self.hass) as session:
|
||||||
|
for rec_id in range(6):
|
||||||
|
if rec_id < 2:
|
||||||
|
timestamp = eleven_days_ago
|
||||||
|
elif rec_id < 4:
|
||||||
|
timestamp = five_days_ago
|
||||||
|
else:
|
||||||
|
timestamp = now
|
||||||
|
|
||||||
|
session.add(
|
||||||
|
RecorderRuns(
|
||||||
|
start=timestamp,
|
||||||
|
created=dt_util.utcnow(),
|
||||||
|
end=timestamp + timedelta(days=1),
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
def test_purge_old_states(self):
|
def test_purge_old_states(self):
|
||||||
"""Test deleting old states."""
|
"""Test deleting old states."""
|
||||||
self._add_test_states()
|
self._add_test_states()
|
||||||
@ -127,6 +154,7 @@ class TestRecorderPurge(unittest.TestCase):
|
|||||||
service_data = {"keep_days": 4}
|
service_data = {"keep_days": 4}
|
||||||
self._add_test_events()
|
self._add_test_events()
|
||||||
self._add_test_states()
|
self._add_test_states()
|
||||||
|
self._add_test_recorder_runs()
|
||||||
|
|
||||||
# make sure we start with 6 states
|
# make sure we start with 6 states
|
||||||
with session_scope(hass=self.hass) as session:
|
with session_scope(hass=self.hass) as session:
|
||||||
@ -136,6 +164,9 @@ class TestRecorderPurge(unittest.TestCase):
|
|||||||
events = session.query(Events).filter(Events.event_type.like("EVENT_TEST%"))
|
events = session.query(Events).filter(Events.event_type.like("EVENT_TEST%"))
|
||||||
assert events.count() == 6
|
assert events.count() == 6
|
||||||
|
|
||||||
|
recorder_runs = session.query(RecorderRuns)
|
||||||
|
assert recorder_runs.count() == 7
|
||||||
|
|
||||||
self.hass.data[DATA_INSTANCE].block_till_done()
|
self.hass.data[DATA_INSTANCE].block_till_done()
|
||||||
|
|
||||||
# run purge method - no service data, use defaults
|
# run purge method - no service data, use defaults
|
||||||
@ -162,6 +193,9 @@ class TestRecorderPurge(unittest.TestCase):
|
|||||||
# now we should only have 2 events left
|
# now we should only have 2 events left
|
||||||
assert events.count() == 2
|
assert events.count() == 2
|
||||||
|
|
||||||
|
# now we should only have 3 recorder runs left
|
||||||
|
assert recorder_runs.count() == 3
|
||||||
|
|
||||||
assert not (
|
assert not (
|
||||||
"EVENT_TEST_PURGE" in (event.event_type for event in events.all())
|
"EVENT_TEST_PURGE" in (event.event_type for event in events.all())
|
||||||
)
|
)
|
||||||
@ -175,6 +209,6 @@ class TestRecorderPurge(unittest.TestCase):
|
|||||||
self.hass.block_till_done()
|
self.hass.block_till_done()
|
||||||
self.hass.data[DATA_INSTANCE].block_till_done()
|
self.hass.data[DATA_INSTANCE].block_till_done()
|
||||||
assert (
|
assert (
|
||||||
mock_logger.debug.mock_calls[3][1][0]
|
mock_logger.debug.mock_calls[4][1][0]
|
||||||
== "Vacuuming SQL DB to free space"
|
== "Vacuuming SQL DB to free space"
|
||||||
)
|
)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user