Skip to content

Commit beeab0f

Browse files
committed
Fix OutgoingRunner main loop and process coordination
1 parent dce6217 commit beeab0f

1 file changed

Lines changed: 37 additions & 0 deletions

File tree

Mailman/Queue/OutgoingRunner.py

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,7 @@ class OutgoingRunner(Runner, BounceMixin):
5757
# Process coordination
5858
_pid_file = os.path.join(mm_cfg.LOCK_DIR, 'outgoing.pid')
5959
_pid_lock = threading.Lock()
60+
_running = False
6061

6162
# Shared processed messages tracking with size limits
6263
_processed_messages = set()
@@ -131,13 +132,45 @@ def __init__(self, slice=None, numslices=1):
131132
self.__logged = False
132133
mailman_log('debug', 'OutgoingRunner: Initializing retry queue')
133134
self.__retryq = Switchboard(mm_cfg.RETRYQUEUE_DIR)
135+
self._running = True
134136
mailman_log('debug', 'OutgoingRunner: Initialization complete')
135137
except Exception as e:
136138
mailman_log('error', 'OutgoingRunner: Initialization failed: %s', str(e))
137139
mailman_log('error', 'OutgoingRunner: Traceback: %s', traceback.format_exc())
138140
self._release_pid_lock()
139141
raise
140142

143+
def run(self):
144+
"""Run the OutgoingRunner main loop."""
145+
if not self._running:
146+
mailman_log('error', 'OutgoingRunner: Not properly initialized')
147+
return
148+
149+
mailman_log('debug', 'OutgoingRunner: Starting main loop')
150+
try:
151+
while self._running and not self._stop:
152+
try:
153+
self._oneloop()
154+
# Sleep briefly to prevent CPU spinning
155+
time.sleep(1)
156+
except Exception as e:
157+
mailman_log('error', 'OutgoingRunner: Error in main loop: %s', str(e))
158+
mailman_log('error', 'OutgoingRunner: Traceback: %s', traceback.format_exc())
159+
# Don't exit on error, just continue the loop
160+
time.sleep(5) # Sleep longer on error
161+
except Exception as e:
162+
mailman_log('error', 'OutgoingRunner: Fatal error in main loop: %s', str(e))
163+
mailman_log('error', 'OutgoingRunner: Traceback: %s', traceback.format_exc())
164+
finally:
165+
self._cleanup()
166+
167+
def stop(self):
168+
"""Stop the OutgoingRunner."""
169+
mailman_log('debug', 'OutgoingRunner: Stopping')
170+
self._running = False
171+
self._stop = True
172+
self._cleanup()
173+
141174
def _acquire_pid_lock(self):
142175
"""Try to acquire the PID lock file."""
143176
try:
@@ -567,6 +600,9 @@ def _validate_bounce(self, recip, code, errmsg):
567600

568601
def _cleanup(self):
569602
"""Clean up resources."""
603+
if not self._running:
604+
return
605+
570606
mailman_log('debug', 'OutgoingRunner: Starting cleanup')
571607
try:
572608
BounceMixin._cleanup(self)
@@ -581,6 +617,7 @@ def _cleanup(self):
581617
finally:
582618
# Always release the PID lock during cleanup
583619
self._release_pid_lock()
620+
self._running = False
584621
mailman_log('debug', 'OutgoingRunner: Cleanup complete')
585622

586623
_doperiodic = BounceMixin._doperiodic

0 commit comments

Comments
 (0)