Added management function similar to 'startcelery' except that it auto-reloads modified website files.
This commit is contained in:
parent
9fced864fe
commit
8001b658c9
|
@ -0,0 +1,70 @@
|
||||||
|
#
|
||||||
|
# OtterTune - runcelery.py
|
||||||
|
#
|
||||||
|
# Copyright (c) 2017-18, Carnegie Mellon University Database Group
|
||||||
|
#
|
||||||
|
import os
|
||||||
|
|
||||||
|
from django.core.management import call_command
|
||||||
|
from django.core.management.base import BaseCommand
|
||||||
|
from django.utils import autoreload
|
||||||
|
from fabric.api import hide, local, settings
|
||||||
|
|
||||||
|
|
||||||
|
class Command(BaseCommand):
|
||||||
|
help = 'Start celery and celerybeat using the auto-reloader.'
|
||||||
|
|
||||||
|
def add_arguments(self, parser):
|
||||||
|
parser.add_argument(
|
||||||
|
'--loglevel',
|
||||||
|
metavar='LOGLEVEL',
|
||||||
|
help='Logging level, choose between DEBUG, INFO, WARNING, ERROR, CRITICAL, or FATAL. '
|
||||||
|
'Defaults to DEBUG if settings.DEBUG is true, otherwise INFO.')
|
||||||
|
parser.add_argument(
|
||||||
|
'--pool',
|
||||||
|
metavar='POOL_CLS',
|
||||||
|
default='threads',
|
||||||
|
help='Pool implementation: prefork (default), eventlet, gevent, solo or threads. '
|
||||||
|
'Default: threads.')
|
||||||
|
parser.add_argument(
|
||||||
|
'--celery-pidfile',
|
||||||
|
metavar='PIDFILE',
|
||||||
|
default='celery.pid',
|
||||||
|
help='File used to store the process pid. The program will not start if this '
|
||||||
|
'file already exists and the pid is still alive. Default: celery.pid.')
|
||||||
|
parser.add_argument(
|
||||||
|
'--celerybeat-pidfile',
|
||||||
|
metavar='PIDFILE',
|
||||||
|
default='celerybeat.pid',
|
||||||
|
help='File used to store the process pid. The program will not start if this '
|
||||||
|
'file already exists and the pid is still alive. Default: celerybeat.pid.')
|
||||||
|
parser.add_argument(
|
||||||
|
'--celery-options',
|
||||||
|
metavar='OPTIONS',
|
||||||
|
help="A comma-separated list of additional options to pass to celery, "
|
||||||
|
"see 'python manage.py celery worker --help' for all available options. "
|
||||||
|
"IMPORTANT: the option's initial -/-- must be omitted. "
|
||||||
|
"Example: '--celery-options purge,include=foo.tasks,q'.")
|
||||||
|
parser.add_argument(
|
||||||
|
'--celerybeat-options',
|
||||||
|
metavar='OPTIONS',
|
||||||
|
help="A comma-separated list of additional options to pass to celerybeat, "
|
||||||
|
"see 'python manage.py celerybeat --help' for all available options. "
|
||||||
|
"IMPORTANT: the option's initial -/-- must be omitted. "
|
||||||
|
"Example: '--celerybeat-options uid=123,q'.")
|
||||||
|
|
||||||
|
def inner_run(self, *args, **options): # pylint: disable=unused-argument
|
||||||
|
autoreload.raise_last_exception()
|
||||||
|
|
||||||
|
for pidfile in (options['celery_pidfile'], options['celerybeat_pidfile']):
|
||||||
|
if os.path.exists(pidfile):
|
||||||
|
with open(pidfile, 'r') as f:
|
||||||
|
pid = f.read().strip()
|
||||||
|
with settings(warn_only=True), hide('commands'): # pylint: disable=not-context-manager
|
||||||
|
local('kill -9 {}'.format(pid))
|
||||||
|
local('rm -f {}'.format(pidfile))
|
||||||
|
call_command('startcelery', silent=True, pipe='', **options)
|
||||||
|
self.stdout.write(self.style.SUCCESS("Successfully reloaded celery and celerybeat."))
|
||||||
|
|
||||||
|
def handle(self, *args, **options):
|
||||||
|
autoreload.main(self.inner_run, None, options)
|
|
@ -17,11 +17,12 @@ class Command(BaseCommand):
|
||||||
max_wait_sec = 15
|
max_wait_sec = 15
|
||||||
|
|
||||||
def add_arguments(self, parser):
|
def add_arguments(self, parser):
|
||||||
parser.add_argument(
|
group = parser.add_mutually_exclusive_group()
|
||||||
|
group.add_argument(
|
||||||
'--celery-only',
|
'--celery-only',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='Start celery only (skip celerybeat).')
|
help='Start celery only (skip celerybeat).')
|
||||||
parser.add_argument(
|
group.add_argument(
|
||||||
'--celerybeat-only',
|
'--celerybeat-only',
|
||||||
action='store_true',
|
action='store_true',
|
||||||
help='Start celerybeat only (skip celery).')
|
help='Start celerybeat only (skip celery).')
|
||||||
|
@ -63,7 +64,8 @@ class Command(BaseCommand):
|
||||||
"IMPORTANT: the option's initial -/-- must be omitted. "
|
"IMPORTANT: the option's initial -/-- must be omitted. "
|
||||||
"Example: '--celerybeat-options uid=123,q'.")
|
"Example: '--celerybeat-options uid=123,q'.")
|
||||||
|
|
||||||
def _parse_suboptions(self, suboptions):
|
@staticmethod
|
||||||
|
def _parse_suboptions(suboptions):
|
||||||
suboptions = suboptions or ''
|
suboptions = suboptions or ''
|
||||||
parsed = []
|
parsed = []
|
||||||
for opt in suboptions.split(','):
|
for opt in suboptions.split(','):
|
||||||
|
@ -73,6 +75,21 @@ class Command(BaseCommand):
|
||||||
return parsed
|
return parsed
|
||||||
|
|
||||||
def handle(self, *args, **options):
|
def handle(self, *args, **options):
|
||||||
|
# Stealth option to disable stdout
|
||||||
|
if options.get('silent', False):
|
||||||
|
self.stdout = open(os.devnull, 'w')
|
||||||
|
|
||||||
|
# Stealth option that assigns where to pipe initial output
|
||||||
|
pipe = options.get('pipe', None)
|
||||||
|
if pipe is None:
|
||||||
|
pipe = '> /dev/null 2>&1'
|
||||||
|
try:
|
||||||
|
if 'celery' in settings.LOGGING['loggers']['celery']['handlers']:
|
||||||
|
logfile = settings.LOGGING['handlers']['celery']['filename']
|
||||||
|
pipe = '>> {} 2>&1'.format(logfile)
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
loglevel = options['loglevel'] or ('DEBUG' if settings.DEBUG else 'INFO')
|
loglevel = options['loglevel'] or ('DEBUG' if settings.DEBUG else 'INFO')
|
||||||
celery_options = [
|
celery_options = [
|
||||||
'--loglevel={}'.format(loglevel),
|
'--loglevel={}'.format(loglevel),
|
||||||
|
@ -84,10 +101,7 @@ class Command(BaseCommand):
|
||||||
'--pidfile={}'.format(options['celerybeat_pidfile']),
|
'--pidfile={}'.format(options['celerybeat_pidfile']),
|
||||||
] + self._parse_suboptions(options['celerybeat_options'])
|
] + self._parse_suboptions(options['celerybeat_options'])
|
||||||
|
|
||||||
pipe = '' if 'console' in settings.LOGGING['loggers']['celery']['handlers'] \
|
with lcd(settings.PROJECT_ROOT), hide('commands'): # pylint: disable=not-context-manager
|
||||||
else '> /dev/null 2>&1'
|
|
||||||
|
|
||||||
with lcd(settings.PROJECT_ROOT), hide('commands'):
|
|
||||||
if not options['celerybeat_only']:
|
if not options['celerybeat_only']:
|
||||||
local(self.celery_cmd(
|
local(self.celery_cmd(
|
||||||
cmd='celery worker', opts=' '.join(celery_options), pipe=pipe))
|
cmd='celery worker', opts=' '.join(celery_options), pipe=pipe))
|
||||||
|
|
Loading…
Reference in New Issue