Ensure storage cleanup doesn't fail (#8531)

This commit is contained in:
Nicolas Mowen 2023-11-07 16:21:43 -07:00 committed by GitHub
parent 0b828ef1ec
commit ca84732574
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 18 additions and 8 deletions

View File

@ -11,7 +11,7 @@ from frigate.config import FrigateConfig, RetainModeEnum
from frigate.const import CACHE_DIR, RECORD_DIR from frigate.const import CACHE_DIR, RECORD_DIR
from frigate.models import Event, Recordings from frigate.models import Event, Recordings
from frigate.record.util import remove_empty_directories, sync_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__) logger = logging.getLogger(__name__)
@ -31,11 +31,7 @@ class RecordingCleanup(threading.Thread):
logger.debug(f"Checking tmp clip {p}.") logger.debug(f"Checking tmp clip {p}.")
if p.stat().st_mtime < (datetime.datetime.now().timestamp() - 60 * 1): if p.stat().st_mtime < (datetime.datetime.now().timestamp() - 60 * 1):
logger.debug("Deleting tmp clip.") logger.debug("Deleting tmp clip.")
clear_and_unlink(p)
# empty contents of file before unlinking https://github.com/blakeblackshear/frigate/issues/4769
with open(p, "w"):
pass
p.unlink(missing_ok=True)
def expire_recordings(self) -> None: def expire_recordings(self) -> None:
"""Delete recordings based on retention config.""" """Delete recordings based on retention config."""

View File

@ -10,6 +10,7 @@ from peewee import fn
from frigate.config import FrigateConfig from frigate.config import FrigateConfig
from frigate.const import RECORD_DIR from frigate.const import RECORD_DIR
from frigate.models import Event, Recordings from frigate.models import Event, Recordings
from frigate.util.builtin import clear_and_unlink
logger = logging.getLogger(__name__) logger = logging.getLogger(__name__)
bandwidth_equation = Recordings.segment_size / ( bandwidth_equation = Recordings.segment_size / (
@ -160,7 +161,7 @@ class StorageMaintainer(threading.Thread):
# Delete recordings not retained indefinitely # Delete recordings not retained indefinitely
if not keep: if not keep:
try: try:
Path(recording.path).unlink(missing_ok=False) clear_and_unlink(Path(recording.path), missing_ok=False)
deleted_recordings.add(recording.id) deleted_recordings.add(recording.id)
deleted_segments_size += recording.segment_size deleted_segments_size += recording.segment_size
except FileNotFoundError: except FileNotFoundError:
@ -188,7 +189,7 @@ class StorageMaintainer(threading.Thread):
break break
try: try:
Path(recording.path).unlink(missing_ok=False) clear_and_unlink(Path(recording.path), missing_ok=False)
deleted_segments_size += recording.segment_size deleted_segments_size += recording.segment_size
deleted_recordings.add(recording.id) deleted_recordings.add(recording.id)
except FileNotFoundError: except FileNotFoundError:

View File

@ -8,6 +8,7 @@ import shlex
import urllib.parse import urllib.parse
from collections import Counter from collections import Counter
from collections.abc import Mapping from collections.abc import Mapping
from pathlib import Path
from typing import Any, Tuple from typing import Any, Tuple
import numpy as np 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( return tomorrow.replace(hour=hour, minute=0, second=0).astimezone(
datetime.timezone.utc 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)