diff options
| author | bwarsaw | 2001-10-18 22:21:40 +0000 |
|---|---|---|
| committer | bwarsaw | 2001-10-18 22:21:40 +0000 |
| commit | e9d5ddb32322b1bdb740e0011d5fe09f9c8e18af (patch) | |
| tree | 6a75b21408e2dd6623e753f250c2c4c710abe7c9 /Mailman/Queue | |
| parent | d8857b760944e978e7e5b0c802fa2b9c245f08e5 (diff) | |
| download | mailman-e9d5ddb32322b1bdb740e0011d5fe09f9c8e18af.tar.gz mailman-e9d5ddb32322b1bdb740e0011d5fe09f9c8e18af.tar.zst mailman-e9d5ddb32322b1bdb740e0011d5fe09f9c8e18af.zip | |
We don't need this file any more, since everything's inlined with
mailmanctl and qrunner.
Diffstat (limited to 'Mailman/Queue')
| -rw-r--r-- | Mailman/Queue/Control.py | 229 |
1 files changed, 0 insertions, 229 deletions
diff --git a/Mailman/Queue/Control.py b/Mailman/Queue/Control.py deleted file mode 100644 index 8646da2cd..000000000 --- a/Mailman/Queue/Control.py +++ /dev/null @@ -1,229 +0,0 @@ -# Copyright (C) 2001 by the Free Software Foundation, Inc. -# -# This program is free software; you can redistribute it and/or -# modify it under the terms of the GNU General Public License -# as published by the Free Software Foundation; either version 2 -# of the License, or (at your option) any later version. -# -# This program is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with this program; if not, write to the Free Software -# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. - -"""Main qrunner control routines. -""" - -import sys -import os -import signal -import time -import errno - -from Mailman import mm_cfg -from Mailman import Utils -from Mailman import LockFile -from Mailman.Logging.Syslog import syslog - -# Useful constants -LOCKFILE = os.path.join(mm_cfg.LOCK_DIR, 'master-qrunner') - -# Since we wake up once per day and refresh the lock, the LOCK_LIFETIME -# needn't be (much) longer than SNOOZE. We pad it 6 hours just to be safe. -LOCK_LIFETIME = mm_cfg.days(1) + mm_cfg.hours(6) -SNOOZE = mm_cfg.days(1) - -# Global dictionary mapping child pids to (qrclass, slice, count) -KIDS = {} - - - -# We want a SIGHUP to re-open all the log files. By closing syslog, it will -# cause a new StampedLogger to be opened the next time a message is logged. -def sighup_handler(signum, frame): - syslog.close() - # SIGHUP all the children so that they'll restart automatically. Don't - # kill the process group because we don't want ourselves to get the - # signal! - for pid in KIDS.keys(): - os.kill(pid, signal.SIGHUP) - # And just to tweak things... - syslog('qrunner', 'Master qrunner caught SIGHUP. Re-opening log files.') - - - -def start_lock_refresher(lock): - # This runs in its own subprocess, and it owns the global qrunner lock. - pid = os.fork() - if pid: - # parent - return pid - # In the child, we simply wake up once per day and refresh the lock. - # Install a SIGHUP handler to break out of the loop cleanly. - class Loop: - def __init__(self): - self._stop = 0 - def stop(self): - self._stop = 1 - def continue_p(self): - return not self._stop - - loop = Loop() - def sighup_handler(signum, frame, loop=loop): - syslog('qrunner', 'Lock refresher caught SIGHUP. Stopping.') - loop.stop() - # Enable the lock refresher's SIGHUP handler - signal.signal(signal.SIGHUP, sighup_handler) - syslog('qrunner', 'Lock refresher started.') - while loop.continue_p(): - time.sleep(SNOOZE) - lock.refresh() - syslog('qrunner', 'Lock refresher exited.') - os._exit(0) - - - -def start_runner(qrclass, slice, count): - pid = os.fork() - if pid: - # parent - return pid - # child - # - # BAW: We need to think of a good way to force the reloading of Mailman - # modules so that a "mailmanctl restart" will utilize any updated code. - # Clearing sys.modules is one way, but it has nasty side effects. Hmm, - # maybe exec'ing a new process image is the right thing to do? - # - # Now instantiate the qrunner class - qrunner = qrclass(slice, count) - def sighup_handler(signum, frame, qrunner=qrunner): - # Exit the qrunner cleanly. - qrunner.stop() - syslog('qrunner', '%s qrunner caught SIGHUP. Stopping.' % - qrunner.__class__.__name__) - # Enable the child's SIGHUP handler - signal.signal(signal.SIGHUP, sighup_handler) - syslog('qrunner', '%s qrunner started.', qrclass.__name__) - qrunner.run() - syslog('qrunner', '%s qrunner exiting.', qrclass.__name__) - os._exit(0) - - - -def master(restart, lock): - # Start up the lock refresher process - refresher_pid = start_lock_refresher(lock) - # Start up all the qrunners - for classname, count in mm_cfg.QRUNNERS: - modulename = 'Mailman.Queue.' + classname - __import__(modulename) - qrclass = getattr(sys.modules[modulename], classname) - for slice in range(count): - info = (qrclass, slice, count) - pid = start_runner(qrclass, slice, count) - KIDS[pid] = info - # Now just wait for children to end, but also catch KeyboardInterrupts - if restart: - restarting = '[restarting]' - else: - restarting = '' - try: - try: - while 1: - try: - pid, status = os.wait() - except OSError, e: - if e.errno <> errno.EINTR: raise - # Just restart the wait() - continue - killsig = status & 0xff - exitstatus = (status >> 8) & 0xff - # What should we do with this information other than log it? - if pid == refresher_pid: - syslog('qrunner', '''\ -Master qrunner detected lock refresher exit - (pid: %d, sig: %d, sts: %d) %s''', - pid, killsig, exitstatus, restarting) - if restart: - refresher_pid = start_lock_refresher(lock) - else: - qrclass, slice, count = KIDS[pid] - syslog('qrunner', '''\ -Master qrunner detected subprocess exit - (pid: %d, sig: %d, sts: %d, class: %s, slice: %d/%d) %s''', - pid, killsig, exitstatus, qrclass.__name__, - slice+1, count, restarting) - del KIDS[pid] - # Now perhaps restart the process - if restart: - newpid = start_runner(qrclass, slice, count) - KIDS[newpid] = (qrclass, slice, count) - except KeyboardInterrupt: - pass - finally: - # Should we leave the main loop for any reason, we want to be sure all - # of our children are exited cleanly. Send SIGHUPs to all the child - # processes and wait for them all to exit. Include the lock - # refresher. - KIDS[refresher_pid] = refresher_pid - for pid in KIDS.keys(): - try: - os.kill(pid, signal.SIGHUP) - except OSError, e: - if e.errno == errno.ESRCH: - # The child has already exited - del KIDS[pid] - # Wait for all the children to go away - Utils.reap(KIDS) - - - -def start(restart, runner=None): - """Main startup function. - - This is called by (the misnamed) cron/qrunner and by bin/mailmanctl. If - optional argument runner is provided, then the named qrunner is run once - followed by a return of this function. If runner is None, then we start - the master qrunner main loop. - """ - # Enable the SIGHUP handler - signal.signal(signal.SIGHUP, sighup_handler) - - # Be sure we can acquire the master qrunner lock. If not, it means some - # other master qrunner daemon is already going. This isn't allowed even - # if we're doing a one-shot runner. Allow the LockFile.TimeOutError to - # propagate to the caller. - lock = LockFile.LockFile(LOCKFILE, LOCK_LIFETIME) - lock.lock(0.5) - - if runner is None: - # Run master in the foreground, storing our own pid in the pid file - fp = open(mm_cfg.PIDFILE, 'w') - print >> fp, os.getpid() - fp.close() - try: - master(restart, lock) - finally: - try: - os.unlink(mm_cfg.PIDFILE) - except EnvironmentError, e: - if e.errno <> errno.ENOENT: raise - # Otherwise ignore this - else: - # One-shot - classname = runner + 'Runner' - modulename = 'Mailman.Queue.%s' % classname - # Let import errors percolate up - __import__(modulename) - class_ = getattr(sys.modules[modulename], classname) - # Subclass to hack in the setting of the stop flag in the - # _doperiodic() subclass. - class Once(class_): - def _doperiodic(self): - self.stop() - runner = Once() - runner.run() |
