2012-02-21 26 views
7

Estoy intentando crear un servicio de Windows para lanzar Apio. Me encontré con un artículo que lo hace usando Task Scheduler. Sin embargo, parece iniciar numerosas instancias de apio y sigue consumiendo memoria hasta que la máquina muere. ¿Hay alguna forma de lanzarlo como un servicio de Windows?¿Cómo crear Apio Windows Service?

Respuesta

12

Recibí la respuesta de otro sitio web. Celeryd (servicio de daemon para Apio) se ejecuta como una aplicación de pasteurización, en la búsqueda de 'Paster Windows Service', llévame here. Describe cómo ejecutar una aplicación de Pilones como un Servicio de Windows. Al ser nuevo en el marco de paster y en el alojamiento de servicios web de Python, no se me pasó por la mente comprobarlo al principio. Pero esa solución funciona para Aplery con un ligero cambio aquí y allá en el guión.

Modifiqué la secuencia de comandos para facilitar la modificación de la configuración de Apio. Los cambios esenciales son:

  1. Crear un archivo INI con la configuración para el servicio de apio (mostrada a continuación)
  2. crear un script Python para crear un servicio de Windows.
configuración

archivo INI (celeryd.ini):

[celery:service] 
service_name = CeleryService 
service_display_name = Celery Service 
service_description = WSCGI Windows Celery Service 
service_logfile = celeryd.log 

script Python para crear servicios de Windows (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:\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) 

Para instalar el servicio que se ejecuta python CeleryService.py install y luego python CeleryService.py start para comenzar el servicio NOTA: Estos comandos se deben ejecutar en línea de comandos con derechos de administrador.

Si es necesario eliminar el servicio, ejecute python CeleryService.py remove.

Estaba intentando alojar Celery como parte de la mejora de mi instalación de RhodeCode. Esta solución parece funcionar. Espero que esto ayude a alguien.

+0

Downvoter (s), por favor indique por qué downvoted . –

+0

¿Cómo se establece un intermediario en un caso así, Redis por ejemplo –

3

La respuesta aceptada no se aplica al uso de apio con una aplicación de Django. Pero me inspiró a encontrar una solución para ejecutar el apio como servicio de Windows con Django. Tenga en cuenta que lo siguiente es solo para proyectos de Django. Puede funcionar con otras aplicaciones con algunas modificaciones.

Crear una celery_service.py archivo (o lo que quiera) dentro de la carpeta principal de su proyecto de Django, mismo nivel que manage.py, con el siguiente contenido:

'''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:\Python27\Scripts' 
# 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) 

Antes de la secuencia de comandos se puede ejecutar, necesita

  1. Instalar pywin32.

  2. Ajuste correctamente PYTHONSCRIPTPATH ​​y projectdir en celery_service.py

PYTHONSCRIPTPATH ​​suele ser la carpeta "Scripts" en la ruta de instalación de la pitón,

por ejemplo,C: \ Scripts \ python27

se agregue al camino de su sistema,

o editar celery_service.py

PYTHONSCRIPTPATH = r'C:\Python27\Scripts' 

projectdir es el nombre del directorio del proyecto Django.

Es el directorio en el mismo nivel de manage.py, no el directorio principal.

Ahora puede instalar/iniciar/detener/eliminar el servicio con:

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

he creado un proyecto de Django de demostración con apio ejecuta como un servicio de Windows:

https://github.com/azalea/django_celery_windows_service

En caso usted está interesado en un ejemplo corriente.

+0

Tal vez me falta algo, pero incluso en la última documentación, parece que 'apical todavía se está utilizando, aunque también menciona el uso de Django para ' daemonize 'Apio: http://ask.github.io/celery/cookbook/daemonizing.html#init-script-celeryd –

+0

@ViteFalcon Gracias por señalarlo. He editado mi redacción. Siéntete libre de editarlo y mejorarlo. – azalea

1

La respuesta de @azalea me ayudó mucho, pero una cosa que me gustaría resaltar aquí es que el servicio (apio_servicio.py) debe instalarse con su usuario/contraseña; de lo contrario, cuando ejecute la función subprocess.Popen(args) in SvcDoRun(), nada sucederá ya que habrá un problema de permiso. Para configurar el usuario/contraseña, puede elegir uno de estos dos métodos:

  1. El uso de línea de comandos:

    python33 .\celeryService1.py --username .\USERNAME --password PASSWORD 
    
  2. Ir al ordenador de gestión (locales)> Servicios y Aplicaciones> Servicios, encontrar su servidor (en el ejemplo de @ azalea, es "apio distribuida de tareas en cola de servicio") y, botón derecho del ratón para abrir Propiedades de la página, de entrada "Esta cuenta" en la ficha Iniciar sesión

Cuestiones relacionadas