From f791ae0af0f362c7afa94b98035dce44b7327def Mon Sep 17 00:00:00 2001 From: Andreas Motl Date: Mon, 21 Jun 2021 03:55:37 +0200 Subject: [PATCH] Protect against running out of disk space Disk space availability will be checked regularly. When a minimum threshold value is undershot, recording will get suspended. After enough disk space will be free again, the recording will be resumed. By default, disk space checks will run each 60 seconds and will check for a minimum free disk space of 10%. --- CHANGES.rst | 1 + saraswati/recorder.py | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 33 insertions(+) diff --git a/CHANGES.rst b/CHANGES.rst index b687423..44b1587 100644 --- a/CHANGES.rst +++ b/CHANGES.rst @@ -7,6 +7,7 @@ in progress =========== - Use 5 minutes recording chunk size as default +- Protect against running out of disk space 2021-06-20 0.2.0 diff --git a/saraswati/recorder.py b/saraswati/recorder.py index f52a41f..d74cad4 100644 --- a/saraswati/recorder.py +++ b/saraswati/recorder.py @@ -3,6 +3,7 @@ # Saraswati is a robust, multi-channel audio recording, transmission and storage system # (c) 2018-2021 Andreas Motl # (c) 2019 Diren Senger +import shutil import threading from functools import partial from typing import List @@ -40,6 +41,12 @@ class SaraswatiRecorder(threading.Thread): """ + # How often to check for disk usage (seconds). + SERVICE_TASK_INTERVAL = 60 + + # How much disk space should be free to sustain recording. + DISK_SPACE_MINIMUM_THRESHOLD = 0.1 + def __init__(self, settings: SaraswatiSettings): super().__init__() @@ -68,13 +75,19 @@ def __init__(self, settings: SaraswatiSettings): # Invoke the pipeline. def run(self): logger.info("Starting audio recorder") + # GLib.idle_add(self.service_idle) self.mainloop.run() + def service_idle(self): + logger.info("Service idle") + def record(self): try: + self.check_disk_usage() self.play() except Exception as ex: logger.error(f"Recording suspended: {ex}") + self.stop() finally: GLib.timeout_add_seconds(self.SERVICE_TASK_INTERVAL, self.record) @@ -89,6 +102,25 @@ def play(self): if success: logger.info("Started recording") + def stop(self): + # https://www.programcreek.com/python/example/69113/gi.repository.GLib.MainLoop + success = False + for i, pipeline in enumerate(self.pipelines): + (outcome, state, pending) = pipeline.gst.get_state(timeout=Gst.SECOND) + if state == Gst.State.PLAYING: + logger.info(f"Stopping pipeline: {pipeline}") + pipeline.gst.set_state(Gst.State.NULL) + success = True + if success: + logger.info("Stopped recording") + + def check_disk_usage(self): + usage = shutil.disk_usage(self.settings.spool_path) + if usage.free / usage.total < self.DISK_SPACE_MINIMUM_THRESHOLD: + raise ResourceWarning( + f"Disk space minimum threshold {self.DISK_SPACE_MINIMUM_THRESHOLD * 100}% reached" + ) + @property def output_location(self): """