python - Sådan oprettes Celery Windows Service?

Indlæg af Hanne Mølgaard Plasc

Problem



Jeg forsøger at oprette en Windows Service for at starte Selleri. Jeg er kommet på tværs af en artikel, der gør det ved hjælp af Task Scheduler. Men det ser ud til at lancere mange selleri instanser og fortsætter med at spise hukommelse indtil maskinen dør. Er der nogen måde at starte det som en Windows-tjeneste? [11]

Bedste reference


Jeg fik svaret fra et andet websted. Celeryd (daemon service for Selleri) kører som en paster ansøgning, leder efter 'Paster Windows Service' føre mig her. Det beskriver, hvordan man kører en Pylons applikation som en Windows Service. At være ny til paster rammer og hosting python web-tjenester, det var ikke min mening at kontrollere det først. Men den løsning fungerer for Selleri med en lille ændring her og der i scriptet. [12]


Jeg har ændret scriptet for at gøre det nemmere at ændre selleriindstillinger. De væsentlige ændringer er:



  1. Opret en INI-fil med indstillingerne for Selleri service (vist nedenfor)

  2. Opret et python-script til at oprette en Windows-tjeneste.



INI-filindstillinger (celeryd.ini):


[celery:service]
service\_name = CeleryService
service\_display\_name = Celery Service
service\_description = WSCGI Windows Celery Service
service\_logfile = celeryd.log


Python script til at oprette Windows Service (CeleryService.py):


"""
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:logscelery.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)


For at installere servicekørslen python CeleryService.py install og derefter python CeleryService.py start for at starte tjenesten. BEMÆRK : Disse kommandoer skal køres i kommandolinje med administratorrettigheder.


Hvis tjenesten skal fjernes, skal du køre python CeleryService.py remove.


Jeg forsøgte at være vært for Selleri som en del af at forbedre min RhodeCode installation. Denne løsning ser ud til at fungere. Håber dette vil hjælpe nogen.

Andre referencer 1


Det accepterede svar gælder ikke for kører selleri med en Django ansøgning. Men det inspirerede mig til at komme med en løsning til at køre selleri som en Windows-service med Django. Bemærk at følgende kun gælder for Django-projekter. Det kan virke med andre applikationer med nogle ændringer.


Opret en fil celery\_service.py (eller hvad du vil) i din Django-projektets øverste niveaumappe, samme niveau som manage.py, med følgende indhold:


'''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

# The directory for celery.log and celery\_service.log
# Default: the directory of this script
INSTDIR = os.path.dirname(os.path.realpath(\_\_file\_\_))
# The path of python Scripts
# Usually it is in PYTHON\_INSTALL\_DIR/Scripts. e.g.
# r'C:Python27Scripts'
# If it is already in system PATH, then it can be set as ''
PYTHONSCRIPTPATH = ''
# The directory name of django project
# Note: it is the directory at the same level of manage.py
# not the parent directory
PROJECTDIR = 'proj'

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

class CeleryService(win32serviceutil.ServiceFramework):

    \_svc\_name\_ = "Celery"
    \_svc\_display\_name\_ = "Celery Distributed Task Queue Service"

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

    def SvcStop(self):
        logging.info('Stopping {name} service ...'.format(name=self.\_svc\_name\_))        
        self.ReportServiceStatus(win32service.SERVICE\_STOP\_PENDING)
        win32event.SetEvent(self.hWaitStop)
        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} worker -f "{log\_path}" -l info'.format(
            celery\_path=os.path.join(PYTHONSCRIPTPATH, 'celery.exe'),
            proj\_dir=PROJECTDIR,
            log\_path=os.path.join(INSTDIR,'celery.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)


Før scriptet kan køres, skal du



  1. Installer pywin32. [13]

  2. Angiv korrekt PYTHONSCRIPTPATH ​​og PROJECTDIR i celery\_service.py



PYTHONSCRIPTPATH ​​er normalt mappen 'Scripts' under din pythons installationsvej,


f.eks. C: \ Python27 \ Scripts


Du kan enten tilføje det til dit system s PATH,


eller rediger celery\_service.py


PYTHONSCRIPTPATH = r'C:Python27Scripts'


PROJECTDIR er navnet på Django-projektet.


Det er biblioteket på samme niveau af manage.py, ikke overordnet mappe.


Nu kan du installere/starte/stoppe/fjerne tjenesten med:


python celery\_service.py install
python celery\_service.py start
python celery\_service.py stop
python celery\_service.py remove


Jeg oprettede et demo Django projekt med selleri kører som en Windows-tjeneste:


https://github.com/azalea/django\_celery\_windows\_service[14]


Hvis du er interesseret i et løbende eksempel.

Andre referencer 2


@azaleas svar hjalp mig meget, men en ting jeg gerne vil fremhæve her er, at tjenesten (celery\_service.py) skal installeres med din bruger/adgangskode, ellers, når du kører subprocess.Popen(args) in SvcDoRun() funktionen, er ingenting vil ske, da der vil være et tilladelsesproblem. For at indstille brugeren/adgangskoden kan du vælge en af ​​to metoder:



  1. Brug af kommandolinje:


    python33 .celeryService1.py --username .USERNAME --password PASSWORD
    

  2. Gå til Computer Management (lokal)> Tjenester og applikationer> Services, find din server (i @azaleas eksempel er det 'Selskabsdistribueret Task Queue Service') og højreklik for at åbne Egenskaber side, skriv 'This konto 'i Log på fanen


Andre referencer 3


Et godt projekt her, men lykkedes ikke at bruge det:
Link til GitHub af django-windows-værktøjerne.
Det gav mig en timeout på den sidste kommandolinje. Har ikke tid nok til at søge hvorfor. [15]


Pakken tillader indstillinger FastCGI, Selleri og Statiske filer fra et Django-projekt på IIS.