2012-02-21 9 views
7

Tôi đang cố tạo một Dịch vụ Windows để khởi chạy Celery. Tôi đã đi qua một bài viết mà nó sử dụng Task Scheduler. Tuy nhiên nó dường như khởi động nhiều trường hợp cần tây và tiếp tục ăn bộ nhớ cho đến khi máy chết. Có cách nào để khởi chạy nó như một dịch vụ Windows không?Cách tạo Dịch vụ Windows Celery?

Trả lời

12

Tôi nhận được câu trả lời từ một trang web khác. Celeryd (dịch vụ daemon cho Celery) chạy như một ứng dụng paster, tìm kiếm 'Paster Windows Service' dẫn tôi here. Nó mô tả cách chạy ứng dụng Giá treo như một Dịch vụ Windows. Là người mới với khuôn khổ paster và lưu trữ các dịch vụ web python, nó không vượt qua tâm trí của tôi để kiểm tra nó lúc đầu. Nhưng giải pháp đó làm việc cho Celery với một chút thay đổi ở đây và trong kịch bản.

Tôi đã sửa đổi tập lệnh để dễ dàng sửa đổi cài đặt Celery hơn. Những thay đổi quan trọng là:

  1. Tạo một tập tin INI với các thiết lập cho dịch vụ cần tây (hình dưới đây)
  2. Tạo một kịch bản python để tạo ra một dịch vụ Windows.
thiết lập

tập tin INI (celeryd.ini):

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

Python script để tạo ra 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:\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) 

Để cài đặt chạy dịch vụ python CeleryService.py install và sau đó python CeleryService.py start để bắt đầu dịch vụ. LƯU Ý: Các lệnh này sẽ được chạy trong dòng lệnh với quyền quản trị viên.

Nếu dịch vụ cần được xóa, hãy chạy python CeleryService.py remove.

Tôi đã cố gắng để lưu trữ Celery như là một phần của việc nâng cấp cài đặt RhodeCode của tôi. Giải pháp này dường như hoạt động. Hy vọng điều này sẽ giúp một ai đó.

+0

Downvoter (s) vui lòng cho biết lý do bạn downvoted . –

+0

Làm thế nào để bạn thiết lập một nhà môi giới trong trường hợp như vậy, Redis ví dụ –

3

Câu trả lời được chấp nhận không áp dụng cho việc chạy cần tây bằng ứng dụng Django. Nhưng nó đã truyền cảm hứng cho tôi để đưa ra một giải pháp cho việc chạy cần tây như một dịch vụ Windows với Django. Lưu ý rằng sau đây chỉ dành cho các dự án Django. Nó có thể làm việc với các ứng dụng khác với một số sửa đổi.

Tạo một celery_service.py tệp (hoặc bất cứ điều gì bạn thích) bên trong thư mục cấp cao nhất dự án Django của bạn, mức độ tương tự như manage.py, với các nội dung sau đây:

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

Trước khi kịch bản có thể được chạy, bạn cần phải

  1. Cài đặt pywin32.

  2. đúng thiết PYTHONSCRIPTPATH ​​và PROJECTDIR trong celery_service.py

PYTHONSCRIPTPATH ​​thường là "Scripts" thư mục theo đường dẫn cài đặt của python của bạn,

ví dụC: \ Python27 \ Scripts

Hoặc thêm nó vào PATH của hệ thống của bạn,

hoặc chỉnh sửa celery_service.py

PYTHONSCRIPTPATH = r'C:\Python27\Scripts' 

PROJECTDIR là tên thư mục của dự án Django.

Đây là thư mục ở cùng cấp độ manage.py, không phải thư mục chính.

Bây giờ bạn có thể cài đặt/start/stop/loại bỏ các dịch vụ với:

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

Tôi tạo ra một dự án Django demo với cần tây chạy như một dịch vụ Windows:

https://github.com/azalea/django_celery_windows_service

Trong trường hợp bạn quan tâm đến một ví dụ đang chạy.

+0

Có lẽ tôi đang thiếu một cái gì đó, nhưng ngay cả trong tài liệu mới nhất, có vẻ như 'celeryd' vẫn đang được sử dụng, mặc dù nó cũng đề cập đến việc sử dụng Django để ' daemonize 'Celery: http://ask.github.io/celery/cookbook/daemonizing.html#init-script-celeryd –

+0

@ViteFalcon Cảm ơn bạn đã chỉ ra. Tôi đã chỉnh sửa từ ngữ của mình. Vui lòng chỉnh sửa và cải thiện nó. – azalea

1

Câu trả lời của @azalea đã giúp tôi rất nhiều, nhưng một điều tôi muốn nhấn mạnh ở đây là dịch vụ (celery_service.py) cần được cài đặt với người dùng/mật khẩu của bạn, nếu không, khi bạn chạy chức năng subprocess.Popen(args) in SvcDoRun(), không có gì sẽ xảy ra vì sẽ có sự cố về quyền. Để thiết lập người dùng/mật khẩu, bạn có thể chọn một trong hai phương pháp:

  1. Sử dụng dòng lệnh:

    python33 .\celeryService1.py --username .\USERNAME --password PASSWORD 
    
  2. Đến Computer Management (địa phương)> Dịch vụ và Ứng dụng> Services, tìm bạn server (trong ví dụ của @ azalea, đó là "Celery Distributed Task Queue Service"), và nhấn chuột phải để mở trang Properties, nhập "Tài khoản này" trong tab Log On