diff --git a/src/core/control.py b/src/core/control.py index c2faf03292c73714abfc34602974815ae486ee5c..7ca70e6ad8c144b32372fb90d07f6b90c3801796 100644 --- a/src/core/control.py +++ b/src/core/control.py @@ -225,18 +225,21 @@ class EngineExecutor(Timer): self.dt = datetime.now() + timedelta(seconds=diff) self.func = func self.param = param - self.update_store() - - if diff < 0: - msg = f"Timer '{self.timer_id}' is due in the past. Executing immediately ..." - self.logger.error(SU.red(msg)) - self.exec_now() - elif diff == 0: - self.logger.info(f"Timer '{self.timer_id}' to be executed immediately") - self.exec_now() + + is_stored = self.update_store() + if not is_stored: + self.logger.info(SU.red("Timer '{self.timer_id}' omitted because it's already existing but dead")) else: - self.exec_timed() - self.start() + if diff < 0: + msg = f"Timer '{self.timer_id}' is due in the past. Executing immediately ..." + self.logger.error(SU.red(msg)) + self.exec_now() + elif diff == 0: + self.logger.info(f"Timer '{self.timer_id}' to be executed immediately") + self.exec_now() + else: + self.exec_timed() + self.start() def wait_for_parent(self): @@ -273,18 +276,34 @@ class EngineExecutor(Timer): def update_store(self): """ Adds the instance to the store and cancels any previously existing commands. + + If a timer with the given ID is already existing but also already executed, + then it is not added to the store. In such case the method returns `False`. + + Returns: + (Boolean): True if the timer has been added to the store """ existing_command = None if self.timer_id in EngineExecutor.timer_store: - existing_command = EngineExecutor.timer_store[self.timer_id] + existing_command = EngineExecutor.timer_store[self.timer_id] + if existing_command: - self.logger.debug(f"Cancelling previous timer with ID: {self.timer_id}") - existing_command.cancel() - if existing_command.child_timer: - self.logger.debug(f"Cancelling child timer with ID: {existing_command.child_timer.timer_id}") + + # Check if existing timer has been executed already -> don't update + if not existing_command.is_alive(): + self.logger.debug(f"Existing previous timer with ID: {self.timer_id}. Don't update.") + return False + + # Still waiting for execution -> update + else: + self.logger.debug(f"Cancelling previous timer with ID: {self.timer_id}") + existing_command.cancel() + if existing_command.child_timer: + self.logger.debug(f"Cancelling child timer with ID: {existing_command.child_timer.timer_id}") EngineExecutor.timer_store[self.timer_id] = self self.logger.debug(f"Created command timer with ID: {self.timer_id}") + return True def is_alive(self): @@ -306,13 +325,13 @@ class EngineExecutor(Timer): @staticmethod def remove_stale_timers(): """ - Removes timers from store which have been executed and are older than one hour. + Removes timers from store which have been executed and are older than 5 hours. """ timers = EngineExecutor.timer_store.values() del_keys = [] for timer in timers: - if timer.dt < datetime.now() - timedelta(seconds=3600): + if timer.dt < datetime.now() - timedelta(hours=5): if not timer.child_timer or (timer.child_timer and not timer.child_timer.is_alive()): timer.logger.debug(f"Removing already executed timer with ID: {timer.timer_id}") del_keys.append(timer.timer_id) @@ -327,16 +346,22 @@ class EngineExecutor(Timer): Prints a list of active timers and inactive timer not older than one hour. """ timers = EngineExecutor.timer_store.values() - msg = "\n [ ENGINE COMMAND QUEUE ]\n" + msg = SU.blue("\n [ ENGINE COMMAND QUEUE ]\n") EngineExecutor.remove_stale_timers() if not timers: - msg += "None available!\n" + msg += "\nNone available!\n" else: for timer in timers: if not timer.parent_timer: - msg += f" => {str(timer)}\n" + line = f" => {str(timer)}\n"# + if timer.is_alive(): + line = SU.green(line) + msg += line if timer.child_timer: - msg += f" => {str(timer.child_timer)}\n" + line = f" => {str(timer.child_timer)}\n" + if timer.child_timer.is_alive(): + line = SU.green(line) + msg += line EngineExecutor.logger.info(msg + "\n")