diff --git a/frigate/record/cleanup.py b/frigate/record/cleanup.py index e6bb41da3..7b3bc7e8d 100644 --- a/frigate/record/cleanup.py +++ b/frigate/record/cleanup.py @@ -11,7 +11,7 @@ from frigate.config import FrigateConfig, RetainModeEnum from frigate.const import CACHE_DIR, RECORD_DIR from frigate.models import Event, Recordings from frigate.record.util import remove_empty_directories, sync_recordings -from frigate.util.builtin import get_tomorrow_at_time +from frigate.util.builtin import clear_and_unlink, get_tomorrow_at_time logger = logging.getLogger(__name__) @@ -31,11 +31,7 @@ class RecordingCleanup(threading.Thread): logger.debug(f"Checking tmp clip {p}.") if p.stat().st_mtime < (datetime.datetime.now().timestamp() - 60 * 1): logger.debug("Deleting tmp clip.") - - # empty contents of file before unlinking https://github.com/blakeblackshear/frigate/issues/4769 - with open(p, "w"): - pass - p.unlink(missing_ok=True) + clear_and_unlink(p) def expire_recordings(self) -> None: """Delete recordings based on retention config.""" diff --git a/frigate/storage.py b/frigate/storage.py index d7be876e2..029c5c388 100644 --- a/frigate/storage.py +++ b/frigate/storage.py @@ -10,6 +10,7 @@ from peewee import fn from frigate.config import FrigateConfig from frigate.const import RECORD_DIR from frigate.models import Event, Recordings +from frigate.util.builtin import clear_and_unlink logger = logging.getLogger(__name__) bandwidth_equation = Recordings.segment_size / ( @@ -160,7 +161,7 @@ class StorageMaintainer(threading.Thread): # Delete recordings not retained indefinitely if not keep: try: - Path(recording.path).unlink(missing_ok=False) + clear_and_unlink(Path(recording.path), missing_ok=False) deleted_recordings.add(recording.id) deleted_segments_size += recording.segment_size except FileNotFoundError: @@ -188,7 +189,7 @@ class StorageMaintainer(threading.Thread): break try: - Path(recording.path).unlink(missing_ok=False) + clear_and_unlink(Path(recording.path), missing_ok=False) deleted_segments_size += recording.segment_size deleted_recordings.add(recording.id) except FileNotFoundError: diff --git a/frigate/util/builtin.py b/frigate/util/builtin.py index b93bfd214..ff30952bb 100644 --- a/frigate/util/builtin.py +++ b/frigate/util/builtin.py @@ -8,6 +8,7 @@ import shlex import urllib.parse from collections import Counter from collections.abc import Mapping +from pathlib import Path from typing import Any, Tuple import numpy as np @@ -269,3 +270,15 @@ def get_tomorrow_at_time(hour: int) -> datetime.datetime: return tomorrow.replace(hour=hour, minute=0, second=0).astimezone( datetime.timezone.utc ) + + +def clear_and_unlink(file: Path, missing_ok: bool = True) -> None: + """clear file then unlink to avoid space retained by file descriptors.""" + if not missing_ok and not file.exists(): + raise FileNotFoundError() + + # empty contents of file before unlinking https://github.com/blakeblackshear/frigate/issues/4769 + with open(file, "w"): + pass + + file.unlink(missing_ok=missing_ok)