python - 如何创建 Celery Windows 服务?

标签 python windows windows-services celery

我正在尝试创建一个 Windows 服务来启动 Celery。我遇到过一篇使用 Task Scheduler 做的文章.然而,它似乎启动了许多 celery 实例并不断消耗内存直到机器死机。有什么方法可以将其作为 Windows 服务启动吗?

最佳答案

我从另一个网站得到了答案。 Celeryd(Celery 的守护程序服务)作为粘贴应用程序运行,搜索“Paster Windows 服务”引导我 here .它描述了如何将 Pylons 应用程序作为 Windows 服务运行。作为 paster 框架和托管 python 网络服务的新手,我一开始并没有想过要检查它。但该解决方案适用于 Celery,只需在脚本中稍作改动即可。

我修改了脚本,以便更轻松地修改 Celery 设置。基本变化是:

  1. 使用 Celery 服务的设置创建一个 INI 文件(如下所示)
  2. 创建一个 python 脚本来创建 Windows 服务。

INI 文件设置(celeryd.ini):

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

创建 Windows 服务的 Python 脚本 (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)

要安装服务,请运行 python CeleryService.py install,然后运行 ​​python CeleryService.py start 以启动服务。 注意:这些命令应在具有管理员权限的命令行中运行。

如果需要删除服务,运行python CeleryService.py remove

我试图托管 Celery 作为增强我的 RhodeCode 安装的一部分。该解决方案似乎有效。希望这会对某人有所帮助。

关于python - 如何创建 Celery Windows 服务?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9378932/

相关文章:

python - 格式化我正在构建的Python员工程序的输出

windows - 适用于 Mac 的 CodeKit - 等效于 Windows?

windows - Windows 服务项目中的 AppData\Roaming 文件夹

python - 如何更改 Powershell 中的路径?

python - 如何使用 boto 获取给定工作流执行的 SWF 事件信息

python - 在 PANDAS 中的第一个非 NaN 之后保留行

windows - 批处理文件 : write a command in fresh made cmd with other title

windows - 如何在 Windows 主机和 Ubuntu18.04 客户机之间创建 Virtualbox 共享文件夹

c# - 更改目标框架后 Windows 服务不会启动

c# - 在 url 调用上重新启动 c# windows 服务