diff --git a/packages/helpermodules/utils/_exit_after.py b/packages/helpermodules/utils/_exit_after.py index ece94ffc40..717915b0ca 100644 --- a/packages/helpermodules/utils/_exit_after.py +++ b/packages/helpermodules/utils/_exit_after.py @@ -1,33 +1,26 @@ +import _thread as thread from threading import Timer -import threading +import sys -class TimeoutException(Exception): - pass +def quit_function(fn_name): + sys.stderr.flush() # Python 3 stderr is likely buffered. + thread.interrupt_main() # raises KeyboardInterrupt def exit_after(s): - ''' - Nutze als Decorator, um einen Timeout für eine Funktion zu erzwingen. - Wirft TimeoutException, wenn die Funktion länger als s Sekunden benötigt. - Basiert auf https://stackoverflow.com/questions/492519/timeout-on-a-function-call. + ''' https://stackoverflow.com/questions/492519/timeout-on-a-function-call + use as decorator to exit process if + function takes longer than s seconds ''' def outer(fn): def inner(*args, **kwargs): - timer = Timer( - s, - lambda: thread_raise(TimeoutException(f"Timeout nach {s} Sekunden in {fn.__name__}"))) + timer = Timer(s, quit_function, args=[fn.__name__]) timer.start() try: - return fn(*args, **kwargs) + result = fn(*args, **kwargs) finally: timer.cancel() + return result return inner return outer - - -def thread_raise(ex): - # Raise Exception im aktuellen Thread (nur für Hauptthread zuverlässig) - import ctypes - tid = threading.get_ident() - ctypes.pythonapi.PyThreadState_SetAsyncExc(ctypes.c_long(tid), ctypes.py_object(ex)) diff --git a/packages/main.py b/packages/main.py index 365b1f791a..34538fd566 100755 --- a/packages/main.py +++ b/packages/main.py @@ -3,11 +3,10 @@ """ # flake8: noqa: E402 import logging -import threading -import sys from helpermodules import logger from helpermodules.utils import run_command, thread_handler -from helpermodules.utils._exit_after import TimeoutException +import threading +import sys # als erstes logging initialisieren, damit auch ImportError geloggt werden logger.setup_logging() @@ -46,9 +45,9 @@ def __init__(self): def handler10Sec(self): """ führt den Algorithmus durch. """ - @exit_after(data.data.general_data.data.control_interval) - def handler_with_control_interval(): - try: + try: + @exit_after(data.data.general_data.data.control_interval) + def handler_with_control_interval(): if (data.data.general_data.data.control_interval / 10) == self.interval_counter: data.data.copy_data() loadvars_.get_values() @@ -70,10 +69,6 @@ def handler_with_control_interval(): self.interval_counter = 1 else: self.interval_counter = self.interval_counter + 1 - except Exception: - log.exception("Fehler im Main-Modul 10s-Handler") - - try: log.info("# ***Start*** ") log.debug(run_command.run_shell_command("top -b -n 1 | head -n 20")) log.debug(f'Drosselung: {run_command.run_shell_command("if which vcgencmd >/dev/null; then vcgencmd get_throttled; else echo not found; fi")}') @@ -91,7 +86,7 @@ def handler_with_control_interval(): logging.debug(line.strip()) Pub().pub("openWB/set/system/time", timecheck.create_timestamp()) handler_with_control_interval() - except TimeoutException: + except KeyboardInterrupt: log.critical("Ausführung durch exit_after gestoppt: "+traceback.format_exc()) except Exception: log.exception("Fehler im Main-Modul") @@ -109,7 +104,7 @@ def handler5MinAlgorithm(self): data.data.general_data.grid_protection() data.data.optional_data.ocpp_transfer_meter_values() data.data.counter_all_data.validate_hierarchy() - except TimeoutException: + except KeyboardInterrupt: log.critical("Ausführung durch exit_after gestoppt: "+traceback.format_exc()) except Exception: log.exception("Fehler im Main-Modul") @@ -144,7 +139,7 @@ def handler5Min(self): general_internal_chargepoint_handler.internal_chargepoint_handler.heartbeat = False with ChangedValuesContext(loadvars_.event_module_update_completed): sub.system_data["system"].update_ip_address() - except TimeoutException: + except KeyboardInterrupt: log.critical("Ausführung durch exit_after gestoppt: "+traceback.format_exc()) except Exception: log.exception("Fehler im Main-Modul") @@ -156,7 +151,7 @@ def handler_midnight(self): thread_errors_path = Path(Path(__file__).resolve().parents[1]/"ramdisk"/"thread_errors.log") with thread_errors_path.open("w") as f: f.write("") - except TimeoutException: + except KeyboardInterrupt: log.critical("Ausführung durch exit_after gestoppt: "+traceback.format_exc()) except Exception: log.exception("Fehler im Main-Modul") @@ -165,7 +160,7 @@ def handler_midnight(self): def handler_random_nightly(self): try: data.data.system_data["system"].thread_backup_and_send_to_cloud() - except TimeoutException: + except KeyboardInterrupt: log.critical("Ausführung durch exit_after gestoppt: "+traceback.format_exc()) except Exception: log.exception("Fehler im Main-Modul") @@ -177,7 +172,7 @@ def handler_hour(self): for cp in data.data.cp_data.values(): calculate_charge_cost(cp) data.data.optional_data.et_get_prices() - except TimeoutException: + except KeyboardInterrupt: log.critical("Ausführung durch exit_after gestoppt: "+traceback.format_exc()) except Exception: log.exception("Fehler im Main-Modul")