diff options
Diffstat (limited to 'Mailman/bin/qrunner.py')
| -rw-r--r-- | Mailman/bin/qrunner.py | 277 |
1 files changed, 0 insertions, 277 deletions
diff --git a/Mailman/bin/qrunner.py b/Mailman/bin/qrunner.py deleted file mode 100644 index b73643c9d..000000000 --- a/Mailman/bin/qrunner.py +++ /dev/null @@ -1,277 +0,0 @@ -# Copyright (C) 2001-2008 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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, -# USA. - -import sys -import signal -import logging -import optparse - -from Mailman import Version -from Mailman import loginit -from Mailman.configuration import config -from Mailman.i18n import _ -from Mailman.initialize import initialize - - -COMMASPACE = ', ' -QRUNNER_SHORTCUTS = {} -log = None - - - -def r_callback(option, opt, value, parser): - dest = getattr(parser.values, option.dest) - parts = value.split(':') - if len(parts) == 1: - runner = parts[0] - rslice = rrange = 1 - elif len(parts) == 3: - runner = parts[0] - try: - rslice = int(parts[1]) - rrange = int(parts[2]) - except ValueError: - parser.print_help() - print >> sys.stderr, _('Bad runner specification: $value') - sys.exit(1) - else: - parser.print_help() - print >> sys.stderr, _('Bad runner specification: $value') - sys.exit(1) - dest.append((runner, rslice, rrange)) - - - -def parseargs(): - parser = optparse.OptionParser(version=Version.MAILMAN_VERSION, - usage=_("""\ -Run one or more qrunners, once or repeatedly. - -Each named runner class is run in round-robin fashion. In other words, the -first named runner is run to consume all the files currently in its -directory. When that qrunner is done, the next one is run to consume all the -files in /its/ directory, and so on. The number of total iterations can be -given on the command line. - -Usage: %prog [options] - --r is required unless -l or -h is given, and its argument must be one of the -names displayed by the -l switch. - -Normally, this script should be started from mailmanctl. Running it -separately or with -o is generally useful only for debugging. -""")) - parser.add_option('-r', '--runner', - metavar='runner[:slice:range]', dest='runners', - type='string', default=[], - action='callback', callback=r_callback, - help=_("""\ -Run the named qrunner, which must be one of the strings returned by the -l -option. Optional slice:range if given, is used to assign multiple qrunner -processes to a queue. range is the total number of qrunners for this queue -while slice is the number of this qrunner from [0..range). - -When using the slice:range form, you must ensure that each qrunner for the -queue is given the same range value. If slice:runner is not given, then 1:1 -is used. - -Multiple -r options may be given, in which case each qrunner will run once in -round-robin fashion. The special runner `All' is shorthand for a qrunner for -each listed by the -l option.""")) - parser.add_option('-o', '--once', - default=False, action='store_true', help=_("""\ -Run each named qrunner exactly once through its main loop. Otherwise, each -qrunner runs indefinitely, until the process receives signal.""")) - parser.add_option('-l', '--list', - default=False, action='store_true', - help=_('List the available qrunner names and exit.')) - parser.add_option('-v', '--verbose', - default=0, action='count', help=_("""\ -Display more debugging information to the logs/qrunner log file.""")) - parser.add_option('-s', '--subproc', - default=False, action='store_true', help=_("""\ -This should only be used when running qrunner as a subprocess of the -mailmanctl startup script. It changes some of the exit-on-error behavior to -work better with that framework.""")) - parser.add_option('-C', '--config', - help=_('Alternative configuration file to use')) - opts, args = parser.parse_args() - if args: - parser.error(_('Unexpected arguments')) - if not opts.runners and not opts.list: - parser.error(_('No runner name given.')) - return parser, opts, args - - - -def make_qrunner(name, slice, range, once=False): - # Several conventions for specifying the runner name are supported. It - # could be one of the shortcut names. Or the name is a full module path, - # use it explicitly. If the name starts with a dot, it's a class name - # relative to the Mailman.queue package. - if name in QRUNNER_SHORTCUTS: - classpath = QRUNNER_SHORTCUTS[name] - elif name.startswith('.'): - classpath = 'Mailman.queue' + name - else: - classpath = name - modulename, classname = classpath.rsplit('.', 1) - try: - __import__(modulename) - except ImportError, e: - if opts.subproc: - # Exit with SIGTERM exit code so the master watcher won't try to - # restart us. - print >> sys.stderr, _('Cannot import runner module: $modulename') - print >> sys.stderr, e - sys.exit(signal.SIGTERM) - else: - raise - qrclass = getattr(sys.modules[modulename], classname) - if once: - # Subclass to hack in the setting of the stop flag in _doperiodic() - class Once(qrclass): - def _doperiodic(self): - self.stop() - qrunner = Once(slice, range) - else: - qrunner = qrclass(slice, range) - return qrunner - - - -def set_signals(loop): - """Set up the signal handlers. - - Signals caught are: SIGTERM, SIGINT, SIGUSR1 and SIGHUP. The latter is - used to re-open the log files. SIGTERM and SIGINT are treated exactly the - same -- they cause qrunner to exit with no restart from the master. - SIGUSR1 also causes qrunner to exit, but the master watcher will restart - it in that case. - - :param loop: A loop queue runner instance. - """ - def sigterm_handler(signum, frame): - # Exit the qrunner cleanly - loop.stop() - loop.status = signal.SIGTERM - log.info('%s qrunner caught SIGTERM. Stopping.', loop.name()) - signal.signal(signal.SIGTERM, sigterm_handler) - def sigint_handler(signum, frame): - # Exit the qrunner cleanly - loop.stop() - loop.status = signal.SIGINT - log.info('%s qrunner caught SIGINT. Stopping.', loop.name()) - signal.signal(signal.SIGINT, sigint_handler) - def sigusr1_handler(signum, frame): - # Exit the qrunner cleanly - loop.stop() - loop.status = signal.SIGUSR1 - log.info('%s qrunner caught SIGUSR1. Stopping.', loop.name()) - signal.signal(signal.SIGUSR1, sigusr1_handler) - # SIGHUP just tells us to rotate our log files. - def sighup_handler(signum, frame): - loginit.reopen() - log.info('%s qrunner caught SIGHUP. Reopening logs.', loop.name()) - signal.signal(signal.SIGHUP, sighup_handler) - - - -def main(): - global log, opts - - parser, opts, args = parseargs() - # If we're not running as a subprocess of mailmanctl, then we'll log to - # stderr in addition to logging to the log files. We do this by passing a - # value of True to propagate, which allows the 'mailman' root logger to - # see the log messages. - initialize(opts.config, propagate_logs=not opts.subproc) - log = logging.getLogger('mailman.qrunner') - - # Calculate the qrunner shortcut names. - for qrunnerpath, slices in config.qrunners.items(): - classname = qrunnerpath.rsplit('.', 1)[1] - if classname.endswith('Runner'): - shortname = classname[:-6].lower() - else: - shortname = classname - QRUNNER_SHORTCUTS[shortname] = qrunnerpath - - if opts.list: - prefixlen = max(len(shortname) for shortname in QRUNNER_SHORTCUTS) - for shortname in sorted(QRUNNER_SHORTCUTS): - runnername = QRUNNER_SHORTCUTS[shortname] - shortname = (' ' * (prefixlen - len(shortname))) + shortname - print _('$shortname runs the $runnername qrunner') - sys.exit(0) - - # Fast track for one infinite runner - if len(opts.runners) == 1 and not opts.once: - qrunner = make_qrunner(*opts.runners[0]) - class Loop: - status = 0 - def __init__(self, qrunner): - self._qrunner = qrunner - def name(self): - return self._qrunner.__class__.__name__ - def stop(self): - self._qrunner.stop() - loop = Loop(qrunner) - set_signals(loop) - # Now start up the main loop - log.info('%s qrunner started.', loop.name()) - qrunner.run() - log.info('%s qrunner exiting.', loop.name()) - else: - # Anything else we have to handle a bit more specially - qrunners = [] - for runner, rslice, rrange in opts.runners: - qrunner = make_qrunner(runner, rslice, rrange, once=True) - qrunners.append(qrunner) - # This class is used to manage the main loop - class Loop: - status = 0 - def __init__(self): - self._isdone = False - def name(self): - return 'Main loop' - def stop(self): - self._isdone = True - def isdone(self): - return self._isdone - loop = Loop() - set_signals(loop) - log.info('Main qrunner loop started.') - while not loop.isdone(): - for qrunner in qrunners: - # In case the SIGTERM came in the middle of this iteration - if loop.isdone(): - break - if opts.verbose: - log.info('Now doing a %s qrunner iteration', - qrunner.__class__.__bases__[0].__name__) - qrunner.run() - if opts.once: - break - log.info('Main qrunner loop exiting.') - # All done - sys.exit(loop.status) - - - -if __name__ == '__main__': - main() |
