99from .notification .atevents import AtEvent , AtEventType
1010from ..util .syncdecorator import synchronized
1111from ..util .timeutil import TimeUtil
12- from ..util .atconstants import *
1312from .address import Address
1413from .atsecondaryconnection import AtSecondaryConnection
1514import queue
@@ -26,44 +25,54 @@ def __init__(self, queue: queue.Queue, atsign: AtSign, address: Address,
2625 self .regex = regex
2726 self .last_received_time = last_received_time
2827 self ._verbose = verbose
28+ self .should_be_running_lock = threading .Lock ()
29+ self .running_lock = threading .Lock ()
2930 super ().__init__ (address , context , verbose )
3031 self ._last_heartbeat_sent_time = TimeUtil .current_time_millis ()
3132 self ._last_heartbeat_ack_time = TimeUtil .current_time_millis ()
3233 self ._heartbeat_interval_millis = 30000
3334 self .start_heart_beat ()
34-
35+
3536 def start_heart_beat (self ):
36- threading .Thread (target = self ._start_heart_beat ).start ()
37-
37+ # Daemon: an abandoned connection's heartbeat must not keep the process alive.
38+ # The stop event makes the loop's wait interruptible, so stop_heart_beat()
39+ # takes effect promptly (the Dart SDK's heartbeat is a cancellable Timer).
40+ self ._heartbeat_stop_event = threading .Event ()
41+ self ._heartbeat_thread = threading .Thread (target = self ._start_heart_beat , daemon = True )
42+ self ._heartbeat_thread .start ()
43+
44+ def stop_heart_beat (self ):
45+ """Stop this connection's heartbeat/restart loop."""
46+ self ._heartbeat_stop_event .set ()
47+
3848 def _start_heart_beat (self ):
39- global should_be_running_lock
40- while True :
41- should_be_running_lock .acquire ()
49+ while not self ._heartbeat_stop_event .is_set ():
50+ self .should_be_running_lock .acquire ()
4251 if self .should_be_running :
43- should_be_running_lock .release ()
52+ self . should_be_running_lock .release ()
4453 if (not self .running ) or (self ._last_heartbeat_sent_time - self ._last_heartbeat_ack_time >= self ._heartbeat_interval_millis ):
4554 try :
4655 print ("Monitor heartbeats not being received" )
4756 self .stop_monitor ()
4857 wait_start_time = TimeUtil .current_time_millis ()
49- running_lock .acquire (blocking = 1 )
58+ self . running_lock .acquire (blocking = 1 )
5059 entered = False
5160 print ((TimeUtil .current_time_millis () - wait_start_time ) < 5000 )
5261 while self .running and ((TimeUtil .current_time_millis () - wait_start_time ) < 5000 ):
5362 entered = True
54- running_lock .release ()
63+ self . running_lock .release ()
5564 print ("Wait 5 seconds for monitor to stop" )
5665 try :
5766 time .sleep (1 )
5867 except Exception as ignore :
5968 pass
6069 if not entered :
61- running_lock .release ()
70+ self . running_lock .release ()
6271 entered = False
63- running_lock .acquire (blocking = 1 )
72+ self . running_lock .acquire (blocking = 1 )
6473 if self .running :
6574 print ("Monitor thread has not stopped, but going to start another one anyway" )
66- running_lock .release ()
75+ self . running_lock .release ()
6776 self .start_monitor ()
6877 except Exception as e :
6978 print ("Monitor restart failed " + str (e ))
@@ -76,42 +85,39 @@ def _start_heart_beat(self):
7685 # Can't do anything, the heartbeat loop will take care of restarting the monitor connection
7786 pass
7887 else :
79- should_be_running_lock .release ()
80- try :
81- time .sleep (self ._heartbeat_interval_millis / 6000 ) # 6 * 1000 (from ms to s)
82- except Exception as ignore :
83- pass
88+ self .should_be_running_lock .release ()
89+ self ._heartbeat_stop_event .wait (self ._heartbeat_interval_millis / 6000 ) # 6 * 1000 (from ms to s)
8490
8591 def start_monitor (self ):
8692 self ._last_heartbeat_sent_time = self ._last_heartbeat_ack_time = TimeUtil .current_time_millis ()
8793
88- should_be_running_lock .acquire (blocking = 1 )
94+ self . should_be_running_lock .acquire (blocking = 1 )
8995 self .should_be_running = True
90- should_be_running_lock .release ()
96+ self . should_be_running_lock .release ()
9197
92- running_lock .acquire (blocking = 1 )
98+ self . running_lock .acquire (blocking = 1 )
9399 if not self .running :
94100 self .running = True
95- running_lock .release ()
101+ self . running_lock .release ()
96102 if not self ._connected :
97103 try :
98104 self ._connect ()
99105 except Exception as e :
100106 print ("startMonitor failed to connect to secondary : " + str (e ))
101107 traceback .print_exc ()
102- running_lock .acquire (blocking = 1 )
108+ self . running_lock .acquire (blocking = 1 )
103109 self .running = False
104- running_lock .release ()
110+ self . running_lock .release ()
105111 return False
106112 self ._run ()
107113 else :
108- running_lock .release ()
114+ self . running_lock .release ()
109115 return True
110116
111117 def stop_monitor (self ):
112- should_be_running_lock .acquire (blocking = 1 )
118+ self . should_be_running_lock .acquire (blocking = 1 )
113119 self .should_be_running = False
114- should_be_running_lock .release ()
120+ self . should_be_running_lock .release ()
115121
116122 self ._last_heartbeat_sent_time = self ._last_heartbeat_ack_time = TimeUtil .current_time_millis ()
117123 self .disconnect ()
@@ -138,9 +144,9 @@ def _run(self):
138144 self .execute_command (command = monitor_cmd , retry_on_exception = True , read_the_response = False )
139145 print ("Monitor started on " + str (self .atsign .to_string ()))
140146 entered = False
141- should_be_running_lock .acquire (blocking = 1 )
147+ self . should_be_running_lock .acquire (blocking = 1 )
142148 while self .should_be_running :
143- should_be_running_lock .release ()
149+ self . should_be_running_lock .release ()
144150 entered = True
145151 first = False
146152 what = "read from connection"
@@ -206,26 +212,26 @@ def _run(self):
206212 at_event = AtEvent (event_type , event_data )
207213 self .queue .put (at_event )
208214
209- should_be_running_lock .acquire (blocking = 1 )
215+ self . should_be_running_lock .acquire (blocking = 1 )
210216 entered = False
211217 if not entered :
212- should_be_running_lock .release ()
218+ self . should_be_running_lock .release ()
213219 entered = False
214220 except Exception as e :
215221 traceback .print_exc ()
216- should_be_running_lock .acquire (blocking = 1 )
222+ self . should_be_running_lock .acquire (blocking = 1 )
217223 if not self .should_be_running :
218- should_be_running_lock .release ()
224+ self . should_be_running_lock .release ()
219225 else :
220- should_be_running_lock .release ()
226+ self . should_be_running_lock .release ()
221227 print ("Monitor failed to " + what + " : " + str (e ))
222228 traceback .print_exc ()
223229 print ("Monitor ending. Monitor heartbeat thread should restart the monitor shortly" )
224230 self .disconnect ()
225231 finally :
226- running_lock .acquire (blocking = 1 )
232+ self . running_lock .acquire (blocking = 1 )
227233 self .running = False
228- running_lock .release ()
234+ self . running_lock .release ()
229235
230236 self .disconnect ()
231237
0 commit comments