12
votes

Comment créer le service Windows de céleri?

J'essaie de créer un service Windows pour lancer le céleri. J'ai rencontré un article qui utilise Planificateur de tâches . Cependant, il semble lancer de nombreuses instances de céleri et continue de manger de la mémoire jusqu'à matriction de la machine. Y a-t-il un moyen de le lancer comme un service Windows?


0 commentaires

5 Réponses :


16
votes

J'ai la réponse d'un autre site Web. Celeryd (Daemon Service for Ceery) est exécuté en tant qu'application de Soulet, à la recherche de 'Spast Windows Service' mène-moi ici . Il décrit comment exécuter une application de pylônes en tant que service Windows. Étant nouveau dans le cadre de diffamation et hébergement de services Web Python, il n'a pas traversé d'avis pour le vérifier au début. Mais cette solution fonctionne pour le céleri avec un léger changement ici et là dans le script.

J'ai modifié le script pour faciliter la modification des paramètres de céleri. Les changements essentiels sont: P>

  1. Créez un fichier INI avec les paramètres du service de céleri (indiqué ci-dessous) LI>
  2. Créez un script Python pour créer un service Windows. LI> ol>

    Paramètres de fichier INI (céleryd.ini): p> xxx pré>

    script python pour créer un service Windows (céleryservice.py): p>

    """
    The most basic (working) Windows service possible.
    Requires Mark Hammond's pywin32 package.  
    Most of the code was taken from a  CherryPy 2.2 example of how to set up a service
    """
    import pkg_resources
    import win32serviceutil
    from paste.script.serve import ServeCommand as Server
    import os, sys
    import ConfigParser
    
    import win32service
    import win32event
    
    SCRIPT_DIR          = os.path.abspath(os.path.dirname(__file__))
    INI_FILE            = 'celeryd.ini'
    SERV_SECTION        = 'celery:service'
    SERV_NAME           = 'service_name'
    SERV_DISPLAY_NAME   = 'service_display_name'
    SERV_DESC           = 'service_description'
    SERV_LOG_FILE       = 'service_logfile'
    SERV_APPLICATION    = 'celeryd'
    SERV_LOG_FILE_VAR   = 'CELERYD_LOG_FILE'
    
    # Default Values
    SERV_NAME_DEFAULT           = 'CeleryService'
    SERV_DISPLAY_NAME_DEFAULT   = 'Celery Service'
    SERV_DESC_DEFAULT           = 'WSCGI Windows Celery Service'
    SERV_LOG_FILE_DEFAULT       = r'D:\logs\celery.log'
    
    class DefaultSettings(object):
        def __init__(self):
            if SCRIPT_DIR:
                os.chdir(SCRIPT_DIR)
            # find the ini file
            self.ini = os.path.join(SCRIPT_DIR,INI_FILE)
            # create a config parser opject and populate it with the ini file
            c = ConfigParser.SafeConfigParser()
            c.read(self.ini)
            self.c = c
    
        def getDefaults(self):
            '''
            Check for and get the default settings
            '''
            if (
                (not self.c.has_section(SERV_SECTION)) or
                (not self.c.has_option(SERV_SECTION, SERV_NAME)) or
                (not self.c.has_option(SERV_SECTION, SERV_DISPLAY_NAME)) or
                (not self.c.has_option(SERV_SECTION, SERV_DESC)) or
                (not self.c.has_option(SERV_SECTION, SERV_LOG_FILE))
                ):
                print 'setting defaults'
                self.setDefaults()
            service_name = self.c.get(SERV_SECTION, SERV_NAME)
            service_display_name = self.c.get(SERV_SECTION, SERV_DISPLAY_NAME)
            service_description = self.c.get(SERV_SECTION, SERV_DESC)
            iniFile = self.ini
            service_logfile = self.c.get(SERV_SECTION, SERV_LOG_FILE)
            return service_name, service_display_name, service_description, iniFile, service_logfile
    
        def setDefaults(self):
            '''
            set and add the default setting to the ini file
            '''
            if not self.c.has_section(SERV_SECTION):
                self.c.add_section(SERV_SECTION)
            self.c.set(SERV_SECTION, SERV_NAME, SERV_NAME_DEFAULT)
            self.c.set(SERV_SECTION, SERV_DISPLAY_NAME, SERV_DISPLAY_NAME_DEFAULT)
            self.c.set(SERV_SECTION, SERV_DESC, SERV_DESC_DEFAULT)
            self.c.set(SERV_SECTION, SERV_LOG_FILE, SERV_LOG_FILE_DEFAULT)
            cfg = file(self.ini, 'wr')
            self.c.write(cfg)
            cfg.close()
            print '''
    you must set the celery:service section service_name, service_display_name,
    and service_description options to define the service 
    in the %s file
    ''' % self.ini
            sys.exit()
    
    
    class CeleryService(win32serviceutil.ServiceFramework):
        """NT Service."""
    
        d = DefaultSettings()
        service_name, service_display_name, service_description, iniFile, logFile = d.getDefaults()
    
        _svc_name_ = service_name
        _svc_display_name_ = service_display_name
        _svc_description_ = service_description
    
        def __init__(self, args):
            win32serviceutil.ServiceFramework.__init__(self, args)
            # create an event that SvcDoRun can wait on and SvcStop
            # can set.
            self.stop_event = win32event.CreateEvent(None, 0, 0, None)
    
        def SvcDoRun(self):
            os.chdir(SCRIPT_DIR)
            s = Server(SERV_APPLICATION)
            os.environ[SERV_LOG_FILE_VAR] = self.logFile
            s.run([self.iniFile])
            win32event.WaitForSingleObject(self.stop_event, win32event.INFINITE)
    
        def SvcStop(self):
            self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
            #win32event.SetEvent(self.stop_event)
            self.ReportServiceStatus(win32service.SERVICE_STOPPED)
            sys.exit()
    
    if __name__ == '__main__':
        win32serviceutil.HandleCommandLine(CeleryService)
    


1 commentaires

Comment définissez-vous un courtier dans un tel cas, Redis par exemple



7
votes

La réponse acceptée ne demande pas en cours d'exécution de céleri avec une application Django. Mais il m'a inspiré pour trouver une solution pour faire fonctionner le céleri en tant que service Windows avec Django. Notez que ce qui suit est pour les projets Django seulement. Il peut fonctionner avec d'autres applications, avec quelques modifications.

La discussion suivante suppose Python> = 3.6 et RabbitMQ sont déjà installés, et rabbitmq-server code> est en cours d'exécution sur localhost code>. p>

Créer un celery_service.py de fichier (ou tout ce que vous aimez) dans votre dossier de niveau supérieur de projet Django, même niveau que manage.py, avec le contenu suivant: p>

python celery_service.py install
python celery_service.py start
python celery_service.py stop
python celery_service.py remove


2 commentaires

Peut-être que je manque quelque chose, mais même dans la dernière documentation, il semble que Celeryd est toujours utilisé, bien qu'il ne mentionne pas également à l'aide de Django pour "démoniser" céleri: Ask.github.IO/celery/Cookbook/...


@Vitefalcon merci de le pointer. J'ai édité mon libellé. N'hésitez pas à éditer et à l'améliorer.



1
votes

La réponse de @azalea m'a beaucoup aidé, mais une chose que j'aime souligner ici est, le service (célery_service.py) doit être installé avec votre utilisateur / mot de passe, sinon, lorsque vous exécutez sous-processus. Popen (ARG) dans SVCDorun () fonction, rien ne se produira car il y aura une question de permission. Pour définir l'utilisateur / mot de passe, vous pouvez choisir l'une des deux méthodes suivantes:

  1. Utilisation de la ligne de commande: XXX

  2. aller à la gestion de l'ordinateur (local)> Services et applications> Services, Recherchez votre serveur (dans l'exemple de @ Azalea, il s'agit de "service de file d'attente de tâches distribuée de céleri"), puis cliquez avec le bouton droit de la souris pour ouvrir la page des propriétés, entrée " Ce compte "dans l'onglet Connexion


0 commentaires

0
votes

Un bon projet ici mais n'a pas réussi à l'utiliser: Lien vers le GitHub of the Django-Windows-Tools . Cela m'a donné un délai d'attente à la dernière ligne de commande. N'a pas assez de temps pour rechercher pourquoi.

Le paquet permet aux paramètres FastCGI, de céleri et de fichiers statiques d'un projet Django sur IIS.


0 commentaires

0
votes

Merci à Azalea, car cela m'a conduit à la voie de la possibilité de créer 2 services Windows avec le céleri 4 sur Windows.

Un pour pouvoir commencer / arrêter plusieurs travailleurs Deuxièmement, pour pouvoir démarrer / arrêter le service de battement et ranger le PID à l'aide de céleri 4. P>

Seulement une mise en garde dans celle-ci que je n'ai pas de solution pour que vous ne puissiez pas redémarrer les travailleurs comme vous avez besoin de Assurez-vous que les processus engendrés pour plusieurs sont arrêtés avant de reculer. p>

travailleurs.py: p> xxx pré>

beatService.py: p>

'''Usage : python celery_service.py install (start / stop / remove)
Run celery as a Windows service
'''
import win32service
import win32serviceutil
import win32api
import win32con
import win32event
import subprocess
import sys
import os
import shlex
import logging
import time
import signal

# The directory for celery_beat.log and celery_beat_service.log
# Default: the directory of this script
INSTDIR = os.path.dirname(os.path.realpath(__file__))
LOGPATH = 'X:\Application\Logs'
# The path of python Scripts
# Usually it is in PYTHON_INSTALL_DIR/Scripts. e.g.
# r'C:\Python27\Scripts'
# If it is already in system PATH, then it can be set as ''
PYTHONSCRIPTPATH = 'C:\Python36\Scripts'
# The directory name of django project
# Note: it is the directory at the same level of manage.py
# not the parent directory
PROJECTDIR = 'PROJECT'

logging.basicConfig(
    filename = os.path.join(LOGPATH, 'celery_beat_service.log'),
    level = logging.DEBUG, 
    format = '[%(asctime)-15s: %(levelname)-7.7s] %(message)s'
)

class CeleryService(win32serviceutil.ServiceFramework):

    _svc_name_ = "CeleryBeat"
    _svc_display_name_ = "CeleryBeat"

    def __init__(self, args):
        win32serviceutil.ServiceFramework.__init__(self, args)
        self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)           

    def SvcStop(self):
        logging.info('Stopping 1 {name} service ...'.format(name=self._svc_name_))        
        self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
        win32event.SetEvent(self.hWaitStop)
        pidno = open("X:\Aplication\Project\celerybeat.pid", "r")
        _pid_id_ = pidid=pidno.read()
        pidno.close()
        logging.info(_pid_id_)
        logging.info('taskkill /F /PID {pidid} ..'.format(pidid=_pid_id_))
        cmdcom = 'taskkill /F /PID {pidid}'.format(pidid=_pid_id_)
        logging.info(cmdcom)
        killargs = shlex.split(cmdcom)
        process = subprocess.Popen(killargs)
        output, error = process.communicate()
        logging.info(output)
        logging.info('Stopping 2 {name} service ...'.format(name=self._svc_name_))
        os.remove("X:\Application\PROJECT\celerybeat.pid")
        logging.info('X:\Application\PROJECT\celerybeat.pid  file removed')
        self.ReportServiceStatus(win32service.SERVICE_STOPPED)
        sys.exit()

    def SvcDoRun(self):
        logging.info('Starting {name} service ...'.format(name=self._svc_name_))
        os.chdir(INSTDIR) # so that proj worker can be found
        logging.info('cwd: ' + os.getcwd())
        self.ReportServiceStatus(win32service.SERVICE_RUNNING)
        command = '"{celery_path}" -A {proj_dir} beat --workdir=X:/Application/Project -f X:/Application/logs/beat.log -l info'.format(
            celery_path=os.path.join(PYTHONSCRIPTPATH, 'celery.exe'),
            proj_dir=PROJECTDIR,
            log_path=os.path.join(LOGPATH,'celery_beat.log'))
        logging.info('command: ' + command)
        args = shlex.split(command)
        proc = subprocess.Popen(args)
        logging.info('pid: {pid}'.format(pid=proc.pid))
        self.timeout = 3000
        while True:
            rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
            if rc == win32event.WAIT_OBJECT_0:
                # stop signal encountered
                # terminate process 'proc'
                PROCESS_TERMINATE = 1
                handle = win32api.OpenProcess(PROCESS_TERMINATE, False, proc.pid)
                win32api.TerminateProcess(handle, -1)
                win32api.CloseHandle(handle)                
                break

if __name__ == '__main__':
   win32serviceutil.HandleCommandLine(CeleryService)


0 commentaires