From 4c678f82b972c87805af79b14b83c239f44bb6f7 Mon Sep 17 00:00:00 2001
From: David Trattnig <david.trattnig@o94.at>
Date: Wed, 3 Jun 2020 11:17:47 +0200
Subject: [PATCH] Clean timer queue and scheduling fixes.

---
 modules/scheduling/scheduler.py | 38 ++++++++++++++++++++++-----------
 1 file changed, 26 insertions(+), 12 deletions(-)

diff --git a/modules/scheduling/scheduler.py b/modules/scheduling/scheduler.py
index 879d2572..b64a9d9d 100644
--- a/modules/scheduling/scheduler.py
+++ b/modules/scheduling/scheduler.py
@@ -75,7 +75,7 @@ class AuraScheduler(threading.Thread):
 
         programme:                              The current radio programme to be played as defined in the local engine database
         active_entry(Show, Track):              This is a Tuple consisting of the currently played `Show` and `Track`
-        message_timer(Array<threading.Timer>):  The message queue of Liquidsoap commands for playlists/tracks to be played
+        message_timer(List<threading.Timer>):   The timer queue of Liquidsoap commands for playlists/entries to be played
     """
     redismessenger = None
     job_result = {}
@@ -140,6 +140,7 @@ class AuraScheduler(threading.Thread):
         while not self.exit_event.is_set():
             try:
                 seconds_to_wait = int(self.config.get("fetching_frequency"))
+                self.logger.info(SimpleUtil.cyan("== start fetching new schedules =="))
                 next_time = datetime.datetime.now() + datetime.timedelta(seconds=seconds_to_wait)
                 self.logger.info("Fetch new programmes every %ss. Next fetching in %ss." % (str(seconds_to_wait), str(next_time)))
                 self.fetch_new_programme()
@@ -156,9 +157,9 @@ class AuraScheduler(threading.Thread):
             except Exception as e:
                 self.logger.critical(SimpleUtil.red("Unhandled error while fetching & scheduling new programme! (%s)" % str(e)), e)
 
-            self.print_message_queue()
+            self.clean_timer_queue()
+            self.print_timer_queue()
             self.exit_event.wait(seconds_to_wait)
-            self.logger.info(SimpleUtil.cyan("== start fetching new schedules =="))
 
 
 
@@ -330,19 +331,31 @@ class AuraScheduler(threading.Thread):
 
 
 
-    def print_message_queue(self):
+    def print_timer_queue(self):
         """
-        Prints the current message queue i.e. playlists in the queue to be played.
+        Prints the current timer queue i.e. playlists in the queue to be played.
         """
         message_queue = ""
         messages = sorted(self.message_timer, key=attrgetter('diff'))
         if not messages:
-            self.logger.warning("There's nothing in the Message Queue!")
+            self.logger.warning("There's nothing in the Timer Queue!")
         else:
             for msg in messages:
                 message_queue += str(msg)+"\n"
 
-            self.logger.info("Message Queue: \n" + message_queue) 
+            self.logger.info("Timer queue: \n" + message_queue) 
+
+
+
+    def clean_timer_queue(self):
+        """
+        Removes inactive timers from the queue.
+        """
+        len_before = len(self.message_timer)
+        self.message_timer[:] = [m for m in self.message_timer if m.is_alive()]
+        len_after = len(self.message_timer)
+        self.logger.info("Removed %s finished timer objects from queue" % (len_before - len_after))
+
 
 
     # ------------------------------------------------------------------------------------------ #
@@ -601,7 +614,7 @@ class AuraScheduler(threading.Thread):
                 if not isinstance(entries, list):
                     raise ValueError("Invalid Entry Group: %s" % str(entries))
                 
-                self.set_entry_timer(entries, fade_in, fade_out)
+                self.set_entries_timer(entries, fade_in, fade_out)
 
                 # Check if it's the last item, which needs special handling
                 if entries[-1] == clean_entries[-1]:
@@ -612,7 +625,7 @@ class AuraScheduler(threading.Thread):
 
 
 
-    def set_entry_timer(self, entries, fade_in, fade_out):
+    def set_entries_timer(self, entries, fade_in, fade_out):
         """
         Creates timer for loading and playing one or multiple entries. Existing timers are 
         updated.
@@ -699,7 +712,8 @@ class AuraScheduler(threading.Thread):
         fade_out_time = 0
 
         # Stop function to be called when schedule ends
-        def do_stop(entry):
+        def do_stop(entries):
+            entry = entries[0]
             self.logger.info(SimpleUtil.cyan("=== stop('%s') ===" % entry))
             transition_type = TransitionType.INSTANT
             if fade_out:
@@ -854,7 +868,7 @@ class AuraScheduler(threading.Thread):
 
         # Remove it from message queue
         self.message_timer.remove(timer)
-        self.logger.info("Removed %s timers for: %s" % (str(count), EngineUtil.get_entries_string(timer.entries)))
+        self.logger.info("Stopped %s timers for: %s" % (str(count), EngineUtil.get_entries_string(timer.entries)))
 
 
 
@@ -932,7 +946,7 @@ class CallFunctionTimer(threading.Timer):
 
         self.logger = logging.getLogger("AuraEngine")
         self.logger.debug("Executing soundsystem command '%s' in %s seconds..." % (str(func.__name__), str(diff)))
-        threading.Timer.__init__(self, diff, func, param)
+        threading.Timer.__init__(self, diff, func, (param,))
 
         if not fadein and not fadeout and not switcher and not loader \
             or fadein and fadeout \
-- 
GitLab