Browse Source

Celery no longer does detaching, you need to use start-stop-daemon,
supervisord, or launchd to daemonize the celery services. This is because
we've had a *lot* of problems with detaching, without any solution in sight.
This means the --detach, --pidfile, --uid, --gid, --chroot, --umask and
--workdir arguments has been removed from celeryd and celerybeat. See
contrib/debian/init.d for example startup scripts for debian, and
contrib/mac/org.celeryq.* for example launchd configuration files for Mac OS
X.

Ask Solem 15 years ago
parent
commit
01a8a0ecbb

+ 1 - 1
celery/beat.py

@@ -154,7 +154,7 @@ class ClockService(object):
     registry = _registry.tasks
     open_schedule = lambda self, filename: shelve.open(filename)
 
-    def __init__(self, logger=None, is_detached=False,
+    def __init__(self, logger=None,
             max_interval=conf.CELERYBEAT_MAX_LOOP_INTERVAL,
             schedule_filename=conf.CELERYBEAT_SCHEDULE_FILENAME):
         self.logger = logger or log.get_default_logger()

+ 8 - 75
celery/bin/celerybeat.py

@@ -17,34 +17,6 @@
     Logging level, choose between ``DEBUG``, ``INFO``, ``WARNING``,
     ``ERROR``, ``CRITICAL``, or ``FATAL``.
 
-.. cmdoption:: -p, --pidfile
-
-    Path to pidfile.
-
-.. cmdoption:: -d, --detach, --daemon
-
-    Run in the background as a daemon.
-
-.. cmdoption:: -u, --uid
-
-    User-id to run ``celerybeat`` as when in daemon mode.
-
-.. cmdoption:: -g, --gid
-
-    Group-id to run ``celerybeat`` as when in daemon mode.
-
-.. cmdoption:: --umask
-
-    umask of the process when in daemon mode.
-
-.. cmdoption:: --workdir
-
-    Directory to change to when in daemon mode.
-
-.. cmdoption:: --chroot
-
-    Change root directory to this path when in daemon mode.
-
 """
 import sys
 import traceback
@@ -62,7 +34,7 @@ STARTUP_INFO_FMT = """
 Configuration ->
     . broker -> %(conninfo)s
     . schedule -> %(schedule)s
-    . sys -> %(logfile)s@%(loglevel)s %(pidfile)s
+    . logfile -> %(logfile)s@%(loglevel)s
 """.strip()
 
 OPTION_LIST = (
@@ -79,34 +51,11 @@ OPTION_LIST = (
             default=conf.CELERYBEAT_LOG_LEVEL,
             action="store", dest="loglevel",
             help="Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL/FATAL."),
-    optparse.make_option('-p', '--pidfile',
-            default=conf.CELERYBEAT_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 celerybeat as when in daemon mode."),
-    optparse.make_option('-g', '--gid', default=None,
-            action="store", dest="gid",
-            help="Group-id to run celerybeat 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 run_clockservice(detach=False, loglevel=conf.CELERYBEAT_LOG_LEVEL,
-        logfile=conf.CELERYBEAT_LOG_FILE, pidfile=conf.CELERYBEAT_PID_FILE,
-        umask=0, uid=None, gid=None, working_directory=None, chroot=None,
+)
+
+
+def run_clockservice(loglevel=conf.CELERYBEAT_LOG_LEVEL,
+        logfile=conf.CELERYBEAT_LOG_FILE,
         schedule=conf.CELERYBEAT_SCHEDULE_FILENAME, **kwargs):
     """Starts the celerybeat clock server."""
 
@@ -129,7 +78,6 @@ def run_clockservice(detach=False, loglevel=conf.CELERYBEAT_LOG_LEVEL,
             "conninfo": info.format_broker_info(),
             "logfile": logfile or "@stderr",
             "loglevel": conf.LOG_LEVELS[loglevel],
-            "pidfile": detach and pidfile or "",
             "schedule": schedule,
     })
 
@@ -138,21 +86,10 @@ def run_clockservice(detach=False, loglevel=conf.CELERYBEAT_LOG_LEVEL,
     platform.set_process_title("celerybeat",
                                info=" ".join(sys.argv[arg_start:]))
     from celery.log import setup_logger, redirect_stdouts_to_logger
-    on_stop = noop
-    if detach:
-        context, on_stop = platform.create_daemon_context(logfile, pidfile,
-                                        chroot_directory=chroot,
-                                        working_directory=working_directory,
-                                        umask=umask)
-        context.open()
-        logger = setup_logger(loglevel, logfile)
-        redirect_stdouts_to_logger(logger, loglevel)
-        platform.set_effective_user(uid, gid)
 
     def _run_clock():
         logger = setup_logger(loglevel, logfile)
-        clockservice = ClockService(logger=logger, is_detached=detach,
-                                    schedule_filename=schedule)
+        clockservice = ClockService(logger=logger, schedule_filename=schedule)
 
         try:
             clockservice.start()
@@ -161,11 +98,7 @@ def run_clockservice(detach=False, loglevel=conf.CELERYBEAT_LOG_LEVEL,
                     "celerybeat raised exception %s: %s\n%s" % (
                             e.__class__, e, traceback.format_exc()))
 
-    try:
-        _run_clock()
-    except:
-        on_stop()
-        raise
+    _run_clock()
 
 
 def parse_options(arguments):

+ 7 - 93
celery/bin/celeryd.py

@@ -17,10 +17,6 @@
     Logging level, choose between ``DEBUG``, ``INFO``, ``WARNING``,
     ``ERROR``, ``CRITICAL``, or ``FATAL``.
 
-.. cmdoption:: -p, --pidfile
-
-    Path to pidfile.
-
 .. cmdoption:: -B, --beat
 
     Also run the ``celerybeat`` periodic task scheduler. Please note that
@@ -30,36 +26,12 @@
 
     Send events that can be captured by monitors like ``celerymon``.
 
-.. cmdoption:: -d, --detach, --daemon
-
-    Run in the background as a daemon.
-
 .. cmdoption:: --discard
 
     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
-
-    Directory to change to when in daemon mode.
-
-.. cmdoption:: --chroot
-
-    Change root directory to this path when in daemon mode.
-
 """
 import os
 import sys
@@ -84,7 +56,7 @@ Configuration ->
 %(queues)s
     . concurrency -> %(concurrency)s
     . loader -> %(loader)s
-    . sys -> logfile:%(logfile)s@%(loglevel)s %(pidfile)s
+    . logfile -> %(logfile)s@%(loglevel)s
     . events -> %(events)s
     . beat -> %(celerybeat)s
 %(tasks)s
@@ -108,9 +80,6 @@ OPTION_LIST = (
     optparse.make_option('-l', '--loglevel', default=conf.CELERYD_LOG_LEVEL,
             action="store", dest="loglevel",
             help="Choose between DEBUG/INFO/WARNING/ERROR/CRITICAL/FATAL."),
-    optparse.make_option('-p', '--pidfile', default=conf.CELERYD_PID_FILE,
-            action="store", dest="pidfile",
-            help="Path to pidfile."),
     optparse.make_option('-B', '--beat', default=False,
             action="store_true", dest="run_clockservice",
             help="Also run the celerybeat periodic task scheduler. \
@@ -118,32 +87,12 @@ OPTION_LIST = (
     optparse.make_option('-E', '--events', default=conf.SEND_EVENTS,
             action="store_true", dest="events",
             help="Send events so celery can be monitored by e.g. celerymon."),
-    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 run_worker(concurrency=conf.CELERYD_CONCURRENCY, detach=False,
+)
+
+
+def run_worker(concurrency=conf.CELERYD_CONCURRENCY,
         loglevel=conf.CELERYD_LOG_LEVEL, logfile=conf.CELERYD_LOG_FILE,
-        discard=False, pidfile=conf.CELERYD_PID_FILE, umask=0,
-        uid=None, gid=None, working_directory=None,
-        chroot=None, run_clockservice=False, events=False, **kwargs):
+        discard=False, run_clockservice=False, events=False, **kwargs):
     """Starts the celery worker server."""
 
     print("Celery %s is starting." % __version__)
@@ -194,7 +143,6 @@ def run_worker(concurrency=conf.CELERYD_CONCURRENCY, detach=False,
             "concurrency": concurrency,
             "loglevel": conf.LOG_LEVELS[loglevel],
             "logfile": logfile or "[stderr]",
-            "pidfile": detach and "pidfile:%s" % pidfile or "",
             "celerybeat": run_clockservice and "ON" or "OFF",
             "events": events and "ON" or "OFF",
             "tasks": tasklist,
@@ -203,30 +151,15 @@ def run_worker(concurrency=conf.CELERYD_CONCURRENCY, detach=False,
 
     print("Celery has started.")
     set_process_status("Running...")
-    on_stop = noop
-    if detach:
-        from celery.log import setup_logger, redirect_stdouts_to_logger
-        context, on_stop = platform.create_daemon_context(logfile, pidfile,
-                                        chroot_directory=chroot,
-                                        working_directory=working_directory,
-                                        umask=umask)
-        context.open()
-        logger = setup_logger(loglevel, logfile)
-        redirect_stdouts_to_logger(logger, loglevel)
-        platform.set_effective_user(uid, gid)
 
     def run_worker():
         worker = WorkController(concurrency=concurrency,
                                 loglevel=loglevel,
                                 logfile=logfile,
                                 embed_clockservice=run_clockservice,
-                                send_events=events,
-                                is_detached=detach)
+                                send_events=events)
         from celery import signals
         signals.worker_init.send(sender=worker)
-        # Install signal handler that restarts celeryd on SIGHUP,
-        # (only on POSIX systems)
-        install_worker_restart_handler(worker)
 
         try:
             worker.start()
@@ -238,28 +171,9 @@ def run_worker(concurrency=conf.CELERYD_CONCURRENCY, detach=False,
         run_worker()
     except:
         set_process_status("Exiting...")
-        on_stop()
         raise
 
 
-def install_worker_restart_handler(worker):
-
-    def restart_worker_sig_handler(signum, frame):
-        """Signal handler restarting the current python program."""
-        worker.logger.info("Restarting celeryd (%s)" % (
-            " ".join(sys.argv)))
-        if worker.is_detached:
-            pid = os.fork()
-            if pid:
-                worker.stop()
-                sys.exit(0)
-        else:
-            worker.stop()
-        os.execv(sys.executable, [sys.executable] + sys.argv)
-
-    platform.install_signal_handler("SIGHUP", restart_worker_sig_handler)
-
-
 def parse_options(arguments):
     """Parse the available options to ``celeryd``."""
     parser = optparse.OptionParser(option_list=OPTION_LIST)

+ 0 - 6
celery/conf.py

@@ -31,15 +31,12 @@ _DEFAULTS = {
     "CELERYD_LOG_FORMAT": DEFAULT_P_LOG_FMT,
     "CELERYD_LOG_LEVEL": "WARN",
     "CELERYD_LOG_FILE": None, # stderr
-    "CELERYD_PID_FILE": "celeryd.pid",
     "CELERYBEAT_SCHEDULE_FILENAME": "celerybeat-schedule",
     "CELERYBEAT_MAX_LOOP_INTERVAL": 5 * 60, # five minutes.
     "CELERYBEAT_LOG_LEVEL": "INFO",
     "CELERYBEAT_LOG_FILE": None, # stderr
-    "CELERYBEAT_PID_FILE": "celerybeat.pid",
     "CELERYMON_LOG_LEVEL": "INFO",
     "CELERYMON_LOG_FILE": None, # stderr
-    "CELERYMON_PID_FILE": "celerymon.pid",
     "CELERYMON_LOG_FORMAT": DEFAULT_LOG_FMT,
     "CELERY_BROADCAST_QUEUE": "celeryctl",
     "CELERY_BROADCAST_EXCHANGE": "celeryctl",
@@ -96,7 +93,6 @@ CELERYD_LOG_FILE = _get("CELERYD_LOG_FILE")
 CELERYD_LOG_LEVEL = _get("CELERYD_LOG_LEVEL",
                         compat=["CELERYD_DAEMON_LOG_LEVEL"])
 CELERYD_LOG_LEVEL = LOG_LEVELS[CELERYD_LOG_LEVEL.upper()]
-CELERYD_PID_FILE = _get("CELERYD_PID_FILE")
 CELERYD_CONCURRENCY = _get("CELERYD_CONCURRENCY")
 
 # <--- Message routing                             <-   --   --- - ----- -- #
@@ -185,14 +181,12 @@ BROKER_CONNECTION_MAX_RETRIES = _get("CELERY_BROKER_CONNECTION_MAX_RETRIES",
 RESULT_EXCHANGE = _get("CELERY_RESULT_EXCHANGE")
 
 # :--- Celery Beat                                  <-   --   --- - ----- -- #
-CELERYBEAT_PID_FILE = _get("CELERYBEAT_PID_FILE")
 CELERYBEAT_LOG_LEVEL = _get("CELERYBEAT_LOG_LEVEL")
 CELERYBEAT_LOG_FILE = _get("CELERYBEAT_LOG_FILE")
 CELERYBEAT_SCHEDULE_FILENAME = _get("CELERYBEAT_SCHEDULE_FILENAME")
 CELERYBEAT_MAX_LOOP_INTERVAL = _get("CELERYBEAT_MAX_LOOP_INTERVAL")
 
 # :--- Celery Monitor                               <-   --   --- - ----- -- #
-CELERYMON_PID_FILE = _get("CELERYMON_PID_FILE")
 CELERYMON_LOG_LEVEL = _get("CELERYMON_LOG_LEVEL")
 CELERYMON_LOG_FILE = _get("CELERYMON_LOG_FILE")
 

+ 0 - 224
celery/platform.py

@@ -1,9 +1,3 @@
-import os
-import sys
-import pwd
-import grp
-import errno
-import atexit
 import signal
 try:
     from setproctitle import setproctitle as _setproctitle
@@ -11,163 +5,8 @@ except ImportError:
     _setproctitle = None
 
 
-CAN_DETACH = True
-try:
-    import resource
-except ImportError:
-    CAN_DETACH = False
-
 from celery.utils import noop
 
-DAEMON_UMASK = 0
-DAEMON_WORKDIR = "/"
-DAEMON_MAXFD = 1024
-DAEMON_REDIRECT_TO = getattr(os, "devnull", "/dev/null")
-
-
-def create_pidlock(pidfile):
-    """Create a PIDFile to be used with python-daemon.
-
-    If the pidfile already exists the program exits with an error message,
-    however if the process it refers to is not running anymore, the pidfile
-    is just deleted.
-
-    """
-    from daemon import pidlockfile
-    from lockfile import LockFailed
-
-    class PIDFile(object):
-
-        def __init__(self, path):
-            self.path = os.path.abspath(path)
-
-        def __enter__(self):
-            try:
-                pidlockfile.write_pid_to_pidfile(self.path)
-            except OSError, exc:
-                raise LockFailed(str(exc))
-            return self
-
-        def __exit__(self, *_exc):
-            self.release()
-
-        def is_locked(self):
-            return os.path.exists(self.path)
-
-        def release(self):
-            try:
-                os.unlink(self.path)
-            except OSError, exc:
-                if exc.errno in (errno.ENOENT, errno.EACCES):
-                    return
-                raise
-
-        def read_pid(self):
-            return pidlockfile.read_pid_from_pidfile(self.path)
-
-        def is_stale(self):
-            pid = self.read_pid()
-            try:
-                os.kill(pid, 0)
-            except os.error, exc:
-                if exc.errno == errno.ESRCH:
-                    sys.stderr.write("Stale pidfile exists. Removing it.\n")
-                    self.release()
-                    return True
-            except TypeError, exc:
-                sys.stderr.write("Broken pidfile found. Removing it.\n")
-                self.release()
-                return True
-            return False
-
-    pidlock = PIDFile(pidfile)
-    if pidlock.is_locked() and not pidlock.is_stale():
-        raise SystemExit(
-                "ERROR: Pidfile (%s) already exists.\n"
-                "Seems we're already running? (PID: %d)" % (
-                    pidfile, pidlock.read_pid()))
-    return pidlock
-
-
-class DaemonContext(object):
-    _is_open = False
-
-    def __init__(self, pidfile=None, chroot_directory=None,
-            working_directory=DAEMON_WORKDIR, umask=DAEMON_UMASK, **kwargs):
-        self.pidfile = pidfile
-        self.chroot_directory = chroot_directory
-        self.working_directory = working_directory
-        self.umask = umask
-
-    def detach(self):
-        if os.fork() == 0: # first child
-            os.setsid() # create new session.
-            if os.fork() > 0: # second child
-                os._exit(0)
-        else:
-            os._exit(0)
-
-    def open(self):
-        from daemon import daemon
-        if self._is_open:
-            return
-
-        self.detach()
-
-        if self.pidfile is not None:
-                self.pidfile.__enter__()
-
-        if self.chroot_directory is not None:
-            daemon.change_root_directory(self.chroot_directory)
-        os.chdir(self.working_directory)
-        os.umask(self.umask)
-
-        daemon.close_all_open_files()
-
-        os.open(DAEMON_REDIRECT_TO, os.O_RDWR)
-        os.dup2(0, 1)
-        os.dup2(0, 2)
-
-        self._is_open = True
-        atexit.register(self.close)
-
-    def close(self):
-        if not self._is_open:
-            return
-        if self.pidfile is not None:
-            self.pidfile.__exit__()
-        self._is_open = False
-
-
-def create_daemon_context(logfile=None, pidfile=None, **options):
-    if not CAN_DETACH:
-        raise RuntimeError(
-                "This operating system doesn't support detach.")
-
-    # set SIGCLD back to the default SIG_DFL (before python-daemon overrode
-    # it) lets the parent wait() for the terminated child process and stops
-    # the 'OSError: [Errno 10] No child processes' problem.
-    reset_signal("SIGCLD")
-
-    # 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()
-
-    options["pidfile"] = pidfile and create_pidlock(pidfile)
-
-    defaults = {"umask": lambda: 0,
-                "chroot_directory": lambda: None,
-                "working_directory": lambda: os.getcwd()}
-
-    for opt_name, opt_default_gen in defaults.items():
-        if opt_name not in options or options[opt_name] is None:
-            options[opt_name] = opt_default_gen()
-
-    context = DaemonContext(**options)
-
-    return context, context.close
-
 
 def reset_signal(signal_name):
     """Reset signal to the default signal handler.
@@ -212,66 +51,3 @@ def set_mp_process_title(progname, info=None):
     from multiprocessing.process import current_process
     return set_process_title("%s.%s" % (progname, current_process().name),
                              info=info)
-
-
-def parse_uid(uid):
-    """Parse user uid.
-
-    uid can be an integer (uid) or a string (username), if it's a username
-    the uid is taken from the system password system.
-
-    """
-    try:
-        return int(uid)
-    except ValueError:
-        return pwd.getpwnam(uid).pw_uid
-
-
-def parse_gid(gid):
-    """Parse group gid.
-
-    gid can be an integer (gid) or a string (group name), if it's a name
-    the gid is taken from the system password system.
-
-    """
-    try:
-        return int(gid)
-    except ValueError:
-        return grp.getgrnam(gid).gr_gid
-
-
-def setegid(gid):
-    """Set effective group id."""
-    gid = parse_uid(gid)
-    if gid != os.getgid():
-        os.setegid(gid)
-
-
-def seteuid(uid):
-    """Set effective user id."""
-    uid = parse_uid(uid)
-    if uid != os.getuid():
-        os.seteuid(uid)
-
-
-def set_effective_user(uid=None, gid=None):
-    """Change privileges to a new user/group.
-
-    If uid and gid is set the effective user/group is set.
-
-    If only uid is set, the effective user is set, and the group is set
-    to the users primary group.
-
-    If only gid is set, the effective group is set.
-
-    """
-    # gid/uid can be int or username/groupname.
-    uid = uid and parse_uid(uid)
-    gid = gid and parse_gid(gid)
-
-    if uid:
-        # If gid isn't defined, get the primary gid of the user.
-        setegid(gid or pwd.getpwuid(uid).pw_gid)
-        seteuid(uid)
-    else:
-        gid and setegid(gid)

+ 0 - 1
celery/tests/test_conf.py

@@ -9,7 +9,6 @@ SETTING_VARS = (
     ("CELERY_DEFAULT_EXCHANGE_TYPE", "DEFAULT_EXCHANGE_TYPE"),
     ("CELERY_DEFAULT_EXCHANGE", "DEFAULT_EXCHANGE"),
     ("CELERYD_CONCURRENCY", "CELERYD_CONCURRENCY"),
-    ("CELERYD_PID_FILE", "CELERYD_PID_FILE"),
     ("CELERYD_LOG_FILE", "CELERYD_LOG_FILE"),
     ("CELERYD_LOG_FORMAT", "CELERYD_LOG_FORMAT"),
 )

+ 1 - 3
celery/tests/test_worker.py

@@ -317,9 +317,7 @@ class TestCarrotListener(unittest.TestCase):
 class TestWorkController(unittest.TestCase):
 
     def setUp(self):
-        self.worker = WorkController(concurrency=1,
-                                     loglevel=0,
-                                     is_detached=False)
+        self.worker = WorkController(concurrency=1, loglevel=0)
         self.worker.logger = MockLogger()
 
     def test_attrs(self):

+ 1 - 8
celery/worker/__init__.py

@@ -67,10 +67,6 @@ class WorkController(object):
 
         The :class:`logging.Logger` instance used for logging.
 
-    .. attribute:: is_detached
-
-        Flag describing if the worker is running as a daemon or not.
-
     .. attribute:: pool
 
         The :class:`multiprocessing.Pool` instance used.
@@ -105,14 +101,12 @@ class WorkController(object):
     _state = None
 
     def __init__(self, concurrency=None, logfile=None, loglevel=None,
-            send_events=conf.SEND_EVENTS,
-            is_detached=False, embed_clockservice=False):
+            send_events=conf.SEND_EVENTS, embed_clockservice=False):
 
         # Options
         self.loglevel = loglevel or self.loglevel
         self.concurrency = concurrency or self.concurrency
         self.logfile = logfile or self.logfile
-        self.is_detached = is_detached
         self.logger = setup_logger(loglevel, logfile)
         self.embed_clockservice = embed_clockservice
         self.send_events = send_events
@@ -139,7 +133,6 @@ class WorkController(object):
         # can be stopped in a sensible short time.
         self.clockservice = self.embed_clockservice and ClockServiceThread(
                                 logger=self.logger,
-                                is_detached=self.is_detached,
                                 max_interval=1) or None
         self.listener = CarrotListener(self.ready_queue,
                                        self.eta_schedule,

+ 0 - 9
setup.py

@@ -75,15 +75,6 @@ install_requires.extend([
     "django-picklefield",
     "billiard>=0.2.1"])
 
-# python-daemon doesn't run on windows, so check current platform
-if platform.system() == "Windows":
-    print("""
-    ***WARNING***
-    I see you are using windows. You will not be able to run celery
-    in daemon mode with the --detach parameter.""")
-else:
-    install_requires.append("python-daemon>=1.4.8")
-
 py_version_info = sys.version_info
 py_major_version = py_version_info[0]
 py_minor_version = py_version_info[1]