4949from memos .memories .activation .kv import KVCacheMemory
5050from memos .memories .activation .vllmkv import VLLMKVCacheItem , VLLMKVCacheMemory
5151from memos .memories .textual .tree import TextualMemoryItem , TreeTextMemory
52- from memos .memos_tools .notification_utils import send_online_bot_notification
5352from memos .templates .mem_scheduler_prompts import MEMORY_ASSEMBLY_TEMPLATE
5453
5554
@@ -127,21 +126,6 @@ def __init__(self, config: BaseSchedulerConfig):
127126 "consume_interval_seconds" , DEFAULT_CONSUME_INTERVAL_SECONDS
128127 )
129128
130- # queue monitor (optional)
131- self ._queue_monitor_thread : threading .Thread | None = None
132- self ._queue_monitor_running : bool = False
133- self .queue_monitor_interval_seconds : float = self .config .get (
134- "queue_monitor_interval_seconds" , 60.0
135- )
136- self .queue_monitor_warn_utilization : float = self .config .get (
137- "queue_monitor_warn_utilization" , 0.7
138- )
139- self .queue_monitor_crit_utilization : float = self .config .get (
140- "queue_monitor_crit_utilization" , 0.9
141- )
142- self .enable_queue_monitor : bool = self .config .get ("enable_queue_monitor" , False )
143- self ._online_bot_callable = None # type: ignore[var-annotated]
144-
145129 # other attributes
146130 self ._context_lock = threading .Lock ()
147131 self .current_user_id : UserID | str | None = None
@@ -541,6 +525,10 @@ def submit_messages(self, messages: ScheduleMessageItem | list[ScheduleMessageIt
541525 logger .error (error_msg )
542526 raise TypeError (error_msg )
543527
528+ if getattr (message , "timestamp" , None ) is None :
529+ with contextlib .suppress (Exception ):
530+ message .timestamp = datetime .utcnow ()
531+
544532 if self .disable_handlers and message .label in self .disable_handlers :
545533 logger .info (f"Skipping disabled handler: { message .label } - { message .content } " )
546534 continue
@@ -555,6 +543,9 @@ def submit_messages(self, messages: ScheduleMessageItem | list[ScheduleMessageIt
555543 logger .info (
556544 f"Submitted message to local queue: { message .label } - { message .content } "
557545 )
546+ with contextlib .suppress (Exception ):
547+ if messages :
548+ self .dispatcher .on_messages_enqueued (messages )
558549
559550 def _submit_web_logs (
560551 self , messages : ScheduleLogForWebItem | list [ScheduleLogForWebItem ]
@@ -706,13 +697,6 @@ def start(self) -> None:
706697 self ._consumer_thread .start ()
707698 logger .info ("Message consumer thread started" )
708699
709- # optionally start queue monitor if enabled and bot callable present
710- if self .enable_queue_monitor and self ._online_bot_callable is not None :
711- try :
712- self .start_queue_monitor (self ._online_bot_callable )
713- except Exception as e :
714- logger .warning (f"Failed to start queue monitor: { e } " )
715-
716700 def stop (self ) -> None :
717701 """Stop all scheduler components gracefully.
718702
@@ -762,9 +746,6 @@ def stop(self) -> None:
762746 self ._cleanup_queues ()
763747 logger .info ("Memory Scheduler stopped completely" )
764748
765- # Stop queue monitor
766- self .stop_queue_monitor ()
767-
768749 @property
769750 def handlers (self ) -> dict [str , Callable ]:
770751 """
@@ -997,16 +978,6 @@ def _fmt_eta(seconds: float | None) -> str:
997978
998979 return True
999980
1000- # ---------------- Queue monitor & notifications ----------------
1001- def set_notification_bots (self , online_bot = None ):
1002- """
1003- Set external notification callables.
1004-
1005- Args:
1006- online_bot: a callable matching dinding_report_bot.online_bot signature
1007- """
1008- self ._online_bot_callable = online_bot
1009-
1010981 def _gather_queue_stats (self ) -> dict :
1011982 """Collect queue/dispatcher stats for reporting."""
1012983 stats : dict [str , int | float | str ] = {}
@@ -1044,71 +1015,3 @@ def _gather_queue_stats(self) -> dict:
10441015 except Exception :
10451016 stats .update ({"running" : 0 , "inflight" : 0 , "handlers" : 0 })
10461017 return stats
1047-
1048- def _queue_monitor_loop (self , online_bot ) -> None :
1049- logger .info (f"Queue monitor started (interval={ self .queue_monitor_interval_seconds } s)" )
1050- self ._queue_monitor_running = True
1051- while self ._queue_monitor_running :
1052- time .sleep (self .queue_monitor_interval_seconds )
1053- try :
1054- stats = self ._gather_queue_stats ()
1055- # decide severity based on utilization if local queue
1056- title_color = "#00956D"
1057- subtitle = "Scheduler"
1058- if not stats .get ("use_redis_queue" ):
1059- util = float (stats .get ("utilization" , 0.0 ))
1060- if util >= self .queue_monitor_crit_utilization :
1061- title_color = "#C62828" # red
1062- subtitle = "Scheduler (CRITICAL)"
1063- elif util >= self .queue_monitor_warn_utilization :
1064- title_color = "#E65100" # orange
1065- subtitle = "Scheduler (WARNING)"
1066-
1067- other_data1 = {
1068- "use_redis_queue" : stats .get ("use_redis_queue" ),
1069- "handlers" : stats .get ("handlers" ),
1070- "running" : stats .get ("running" ),
1071- "inflight" : stats .get ("inflight" ),
1072- }
1073- if not stats .get ("use_redis_queue" ):
1074- other_data2 = {
1075- "qsize" : stats .get ("qsize" ),
1076- "unfinished_tasks" : stats .get ("unfinished_tasks" ),
1077- "maxsize" : stats .get ("maxsize" ),
1078- "utilization" : f"{ float (stats .get ('utilization' , 0.0 )):.2%} " ,
1079- }
1080- else :
1081- other_data2 = {
1082- "redis_mode" : True ,
1083- }
1084-
1085- send_online_bot_notification (
1086- online_bot = online_bot ,
1087- header_name = "Scheduler Queue" ,
1088- sub_title_name = subtitle ,
1089- title_color = title_color ,
1090- other_data1 = other_data1 ,
1091- other_data2 = other_data2 ,
1092- emoji = {"Runtime" : "🧠" , "Queue" : "📬" },
1093- )
1094- except Exception as e :
1095- logger .warning (f"Queue monitor iteration failed: { e } " )
1096- logger .info ("Queue monitor stopped" )
1097-
1098- def start_queue_monitor (self , online_bot ) -> None :
1099- if self ._queue_monitor_thread and self ._queue_monitor_thread .is_alive ():
1100- return
1101- self ._online_bot_callable = online_bot
1102- self ._queue_monitor_thread = threading .Thread (
1103- target = self ._queue_monitor_loop ,
1104- args = (online_bot ,),
1105- daemon = True ,
1106- name = "QueueMonitorThread" ,
1107- )
1108- self ._queue_monitor_thread .start ()
1109-
1110- def stop_queue_monitor (self ) -> None :
1111- self ._queue_monitor_running = False
1112- if self ._queue_monitor_thread and self ._queue_monitor_thread .is_alive ():
1113- with contextlib .suppress (Exception ):
1114- self ._queue_monitor_thread .join (timeout = 2.0 )
0 commit comments