|
@@ -29,17 +29,17 @@
|
|
|
Discard all waiting tasks before the daemon is started.
|
|
|
**WARNING**: This is unrecoverable, and the tasks will be
|
|
|
deleted from the messaging server.
|
|
|
-
|
|
|
+
|
|
|
.. cmdoption:: -u, --uid
|
|
|
|
|
|
User-id to run ``celeryd`` as when in daemon mode.
|
|
|
|
|
|
.. cmdoption:: -g, --gid
|
|
|
-
|
|
|
+
|
|
|
Group-id to run ``celeryd`` as when in daemon mode.
|
|
|
|
|
|
.. cmdoption:: --umask
|
|
|
-
|
|
|
+
|
|
|
umask of the process when in daemon mode.
|
|
|
|
|
|
.. cmdoption:: --workdir
|
|
@@ -62,6 +62,8 @@ from django.conf import settings
|
|
|
from celery.log import emergency_error
|
|
|
from celery.conf import LOG_LEVELS, DAEMON_LOG_FILE, DAEMON_LOG_LEVEL
|
|
|
from celery.conf import DAEMON_CONCURRENCY, DAEMON_PID_FILE
|
|
|
+from celery.log import setup_logger
|
|
|
+from celery.messaging import TaskConsumer
|
|
|
from celery import conf
|
|
|
from celery import discovery
|
|
|
from celery.task import discard_all
|
|
@@ -76,12 +78,50 @@ import errno
|
|
|
|
|
|
STARTUP_INFO_FMT = """
|
|
|
* Celery loading with the following configuration
|
|
|
- * Broker -> amqp://%(vhost)s@%(host)s:%(port)s
|
|
|
+ * Broker -> amqp://%(vhost)s@%(host)s:%(port)s
|
|
|
* Exchange -> %(exchange)s (%(exchange_type)s)
|
|
|
* Consumer -> Queue:%(consumer_queue)s Routing:%(consumer_rkey)s
|
|
|
* Concurrency:%(concurrency)s
|
|
|
""".strip()
|
|
|
|
|
|
+OPTION_LIST = (
|
|
|
+ optparse.make_option('-c', '--concurrency', default=DAEMON_CONCURRENCY,
|
|
|
+ action="store", dest="concurrency", type="int",
|
|
|
+ help="Number of child processes processing the queue."),
|
|
|
+ optparse.make_option('--discard', default=False,
|
|
|
+ action="store_true", dest="discard",
|
|
|
+ help="Discard all waiting tasks before the server is started. "
|
|
|
+ "WARNING: This is unrecoverable, and the tasks will be "
|
|
|
+ "deleted from the messaging server."),
|
|
|
+ optparse.make_option('-f', '--logfile', default=DAEMON_LOG_FILE,
|
|
|
+ action="store", dest="logfile",
|
|
|
+ help="Path to log file."),
|
|
|
+ optparse.make_option('-l', '--loglevel', default=DAEMON_LOG_LEVEL,
|
|
|
+ action="store", dest="loglevel",
|
|
|
+ help="Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL/FATAL."),
|
|
|
+ optparse.make_option('-p', '--pidfile', default=DAEMON_PID_FILE,
|
|
|
+ action="store", dest="pidfile",
|
|
|
+ help="Path to pidfile."),
|
|
|
+ optparse.make_option('-d', '--detach', '--daemon', default=False,
|
|
|
+ action="store_true", dest="detach",
|
|
|
+ help="Run in the background as a daemon."),
|
|
|
+ optparse.make_option('-u', '--uid', default=None,
|
|
|
+ action="store", dest="uid",
|
|
|
+ help="User-id to run celeryd as when in daemon mode."),
|
|
|
+ optparse.make_option('-g', '--gid', default=None,
|
|
|
+ action="store", dest="gid",
|
|
|
+ help="Group-id to run celeryd as when in daemon mode."),
|
|
|
+ optparse.make_option('--umask', default=0,
|
|
|
+ action="store", type="int", dest="umask",
|
|
|
+ help="umask of the process when in daemon mode."),
|
|
|
+ optparse.make_option('--workdir', default=None,
|
|
|
+ action="store", dest="working_directory",
|
|
|
+ help="Directory to change to when in daemon mode."),
|
|
|
+ optparse.make_option('--chroot', default=None,
|
|
|
+ action="store", dest="chroot",
|
|
|
+ help="Change root directory to this path when in daemon mode."),
|
|
|
+ )
|
|
|
+
|
|
|
|
|
|
def acquire_pidlock(pidfile):
|
|
|
"""Get the :class:`daemon.pidlockfile.PIDLockFile` handler for
|
|
@@ -103,7 +143,7 @@ def acquire_pidlock(pidfile):
|
|
|
except os.error, exc:
|
|
|
if exc.errno == errno.ESRCH:
|
|
|
sys.stderr.write("Stale pidfile exists. Removing it.\n")
|
|
|
- pidlock.release()
|
|
|
+ pidlock.release()
|
|
|
return
|
|
|
else:
|
|
|
raise SystemExit(
|
|
@@ -113,11 +153,12 @@ def acquire_pidlock(pidfile):
|
|
|
return pidlock
|
|
|
|
|
|
|
|
|
-def run_worker(concurrency=DAEMON_CONCURRENCY, daemon=False,
|
|
|
+def run_worker(concurrency=DAEMON_CONCURRENCY, detach=False,
|
|
|
loglevel=DAEMON_LOG_LEVEL, logfile=DAEMON_LOG_FILE, discard=False,
|
|
|
pidfile=DAEMON_PID_FILE, umask=0, uid=None, gid=None,
|
|
|
working_directory=None, chroot=None, **kwargs):
|
|
|
- """Run the celery daemon."""
|
|
|
+ """Starts the celery worker server."""
|
|
|
+
|
|
|
if not concurrency:
|
|
|
concurrency = multiprocessing.cpu_count()
|
|
|
if settings.DATABASE_ENGINE == "sqlite3" and concurrency > 1:
|
|
@@ -126,16 +167,30 @@ def run_worker(concurrency=DAEMON_CONCURRENCY, daemon=False,
|
|
|
"concurrency. We'll be using a single process only.",
|
|
|
UserWarning)
|
|
|
concurrency = 1
|
|
|
-
|
|
|
+
|
|
|
+ # Setup logging
|
|
|
if not isinstance(loglevel, int):
|
|
|
loglevel = LOG_LEVELS[loglevel.upper()]
|
|
|
+ if not detach:
|
|
|
+ logfile = None # log to stderr when not running in the background.
|
|
|
+ logger = setup_logger(logfile=logfile, loglevel=loglevel)
|
|
|
+
|
|
|
+ def say(msg):
|
|
|
+ """Log the message using loglevel ``INFO`` if running in the
|
|
|
+ background, else just print the message to ``stdout``."""
|
|
|
+ if detach:
|
|
|
+ return logger.info(msg)
|
|
|
+ print(msg)
|
|
|
|
|
|
if discard:
|
|
|
discarded_count = discard_all()
|
|
|
what = discard_count > 1 and "messages" or "message"
|
|
|
- sys.stderr.write("Discard: Erased %d %s from the queue.\n" % (
|
|
|
- discarded_count, what))
|
|
|
- startup_info = STARTUP_INFO_FMT % {
|
|
|
+ say("discard: Erased %d %s from the queue.\n" % (
|
|
|
+ discarded_count, what))
|
|
|
+
|
|
|
+ # Dump configuration to screen so we have some basic information
|
|
|
+ # when users sends e-mails.
|
|
|
+ say(STARTUP_INFO_FMT % {
|
|
|
"vhost": settings.AMQP_VHOST,
|
|
|
"host": settings.AMQP_SERVER,
|
|
|
"port": settings.AMQP_PORT,
|
|
@@ -147,20 +202,20 @@ def run_worker(concurrency=DAEMON_CONCURRENCY, daemon=False,
|
|
|
"concurrency": concurrency,
|
|
|
"loglevel": loglevel,
|
|
|
"pidfile": pidfile,
|
|
|
- }
|
|
|
- sys.stderr.write(startup_info + "\n")
|
|
|
- if daemon:
|
|
|
+ })
|
|
|
+
|
|
|
+ if detach:
|
|
|
# Since without stderr any errors will be silently suppressed,
|
|
|
# we need to know that we have access to the logfile
|
|
|
+ if logfile:
|
|
|
+ open(logfile, "a").close()
|
|
|
pidlock = acquire_pidlock(pidfile)
|
|
|
if not umask:
|
|
|
umask = 0
|
|
|
- if logfile:
|
|
|
- open(logfile, "a").close()
|
|
|
uid = uid and int(uid) or os.geteuid()
|
|
|
gid = gid and int(gid) or os.getegid()
|
|
|
working_directory = working_directory or os.getcwd()
|
|
|
- sys.stderr.write("* Launching celeryd in the background...\n")
|
|
|
+ print("* Launching celeryd in the background...")
|
|
|
context = DaemonContext(chroot_directory=chroot,
|
|
|
working_directory=working_directory,
|
|
|
umask=umask,
|
|
@@ -168,64 +223,23 @@ def run_worker(concurrency=DAEMON_CONCURRENCY, daemon=False,
|
|
|
uid=uid,
|
|
|
gid=gid)
|
|
|
context.open()
|
|
|
- else:
|
|
|
- logfile = None # log to stderr when not running as daemon.
|
|
|
|
|
|
discovery.autodiscover()
|
|
|
- celeryd = WorkController(concurrency=concurrency,
|
|
|
- loglevel=loglevel,
|
|
|
- logfile=logfile,
|
|
|
- is_detached=daemon)
|
|
|
+ worker = WorkController(concurrency=concurrency,
|
|
|
+ loglevel=loglevel,
|
|
|
+ logfile=logfile,
|
|
|
+ is_detached=detach)
|
|
|
try:
|
|
|
- celeryd.run()
|
|
|
+ worker.run()
|
|
|
except Exception, e:
|
|
|
emergency_error(logfile, "celeryd raised exception %s: %s\n%s" % (
|
|
|
e.__class__, e, traceback.format_exc()))
|
|
|
except:
|
|
|
- if daemon:
|
|
|
+ if context:
|
|
|
context.close()
|
|
|
raise
|
|
|
|
|
|
|
|
|
-OPTION_LIST = (
|
|
|
- optparse.make_option('-c', '--concurrency', default=DAEMON_CONCURRENCY,
|
|
|
- action="store", dest="concurrency", type="int",
|
|
|
- help="Number of child processes processing the queue."),
|
|
|
- optparse.make_option('--discard', default=False,
|
|
|
- action="store_true", dest="discard",
|
|
|
- help="Discard all waiting tasks before the daemon is started. "
|
|
|
- "WARNING: This is unrecoverable, and the tasks will be "
|
|
|
- "deleted from the messaging server."),
|
|
|
- optparse.make_option('-f', '--logfile', default=DAEMON_LOG_FILE,
|
|
|
- action="store", dest="logfile",
|
|
|
- help="Path to log file."),
|
|
|
- optparse.make_option('-l', '--loglevel', default=DAEMON_LOG_LEVEL,
|
|
|
- action="store", dest="loglevel",
|
|
|
- help="Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL/FATAL."),
|
|
|
- optparse.make_option('-p', '--pidfile', default=DAEMON_PID_FILE,
|
|
|
- action="store", dest="pidfile",
|
|
|
- help="Path to pidfile."),
|
|
|
- optparse.make_option('-d', '--detach', '--daemon', default=False,
|
|
|
- action="store_true", dest="daemon",
|
|
|
- help="Run in the background as a daemon."),
|
|
|
- optparse.make_option('-u', '--uid', default=None,
|
|
|
- action="store", dest="uid",
|
|
|
- help="User-id to run celeryd as when in daemon mode."),
|
|
|
- optparse.make_option('-g', '--gid', default=None,
|
|
|
- action="store", dest="gid",
|
|
|
- help="Group-id to run celeryd as when in daemon mode."),
|
|
|
- optparse.make_option('--umask', default=0,
|
|
|
- action="store", type="int", dest="umask",
|
|
|
- help="umask of the process when in daemon mode."),
|
|
|
- optparse.make_option('--workdir', default=None,
|
|
|
- action="store", dest="working_directory",
|
|
|
- help="Directory to change to when in daemon mode."),
|
|
|
- optparse.make_option('--chroot', default=None,
|
|
|
- action="store", dest="chroot",
|
|
|
- help="Change root directory to this path when in daemon mode."),
|
|
|
- )
|
|
|
-
|
|
|
-
|
|
|
def parse_options(arguments):
|
|
|
"""Parse the available options to ``celeryd``."""
|
|
|
parser = optparse.OptionParser(option_list=OPTION_LIST)
|