簡體   English   中英

從多處理開始芹菜工人

[英]Starting celery worker from multiprocessing

我是芹菜的新手。 我見過的所有例子都是從命令行開始的芹菜工作者。 例如:

$ celery -A proj worker -l info

我正在開始一個關於彈性beanstalk的項目,並認為將worker作為我的web應用程序的子進程會很好。 我嘗試使用多處理,它似乎工作。 我想知道這是不是一個好主意,或者是否有一些缺點。

import celery
import multiprocessing


class WorkerProcess(multiprocessing.Process):
    def __init__(self):
        super().__init__(name='celery_worker_process')

    def run(self):
        argv = [
            'worker',
            '--loglevel=WARNING',
            '--hostname=local',
        ]
        app.worker_main(argv)


def start_celery():
    global worker_process
    worker_process = WorkerProcess()
    worker_process.start()


def stop_celery():
    global worker_process
    if worker_process:
        worker_process.terminate()
        worker_process = None


worker_name = 'celery@local'
worker_process = None

app = celery.Celery()
app.config_from_object('celery_app.celeryconfig')

看起來像一個不錯的選擇,絕對不是唯一的選擇,但一個好的:)

您可能想要研究的一件事(您可能已經這樣做了)是將自動縮放與Celery隊列的大小相關聯。 因此,只有在隊列增長時才能擴展。

當然Celery在內部做了類似的事情,所以沒有太大的區別。 我能想到的唯一障礙是外部資源(例如數據庫連接)的處理,這可能是一個問題,但完全取決於您使用Celery做什么。

如果有人感興趣,我確實使用運行Python 3.4的預配置AMI服務器在Elastic Beanstalk上工作。 運行Debian Jessie的基於Docker的服務器遇到了很多問題。 也許與端口重新映射有關。 Docker是一種黑盒子,我發現很難處理和調試。 幸運的是,AWS的優秀人員剛剛在2015年4月8日添加了一個非docker Python 3.4選項。

我做了很多搜索,以便部署和工作。 我看到很多沒有答案的問題。 所以這是我非常簡單的部署python 3.4 / flask / celery進程。

芹菜你可以只是pip安裝。 您需要使用config命令或container_command從配置文件安裝rabbitmq。 我在上傳的項目zip中使用了一個腳本,因此使用腳本需要一個container_command(在安裝項目之前會發生常規的eb config命令)。

[yourapproot] / ebextensions / 05_install_rabbitmq.config:

container_commands:
  01RunScript:
    command: bash ./init_scripts/app_setup.sh

[yourapproot] /init_scripts/app_setup.sh:

#!/usr/bin/env bash

# Download and install Erlang
yum install erlang

# Download the latest RabbitMQ package using wget:
wget http://www.rabbitmq.com/releases/rabbitmq-server/v3.5.1/rabbitmq-server-3.5.1-1.noarch.rpm

# Install rabbit
rpm --import http://www.rabbitmq.com/rabbitmq-signing-key-public.asc
yum -y install rabbitmq-server-3.5.1-1.noarch.rpm

# Start server
/sbin/service rabbitmq-server start

我正在做一個燒瓶應用程序,所以我在第一次請求之前啟動了工作人員:

@app.before_first_request
def before_first_request():
    task_mgr.start_celery()

task_mgr創建芹菜應用程序對象(我稱之為芹菜,因為燒瓶app對象是應用程序)。 對於一個簡單的任務管理器來說,-Ofair非常重要。 任務預取有各種奇怪的行為。 這可能是默認的?

task_mgr / task_mgr.py:

import celery as celery_module
import multiprocessing


class WorkerProcess(multiprocessing.Process):
    def __init__(self):
        super().__init__(name='celery_worker_process')

    def run(self):
        argv = [
            'worker',
            '--loglevel=WARNING',
            '--hostname=local',
            '-Ofair',
        ]
        celery.worker_main(argv)


def start_celery():
    global worker_process
    multiprocessing.set_start_method('fork')  # 'spawn' seems to work also
    worker_process = WorkerProcess()
    worker_process.start()


def stop_celery():
    global worker_process
    if worker_process:
        worker_process.terminate()
        worker_process = None


worker_name = 'celery@local'
worker_process = None

celery = celery_module.Celery()
celery.config_from_object('task_mgr.celery_config')

到目前為止,我的配置非常簡單:

task_mgr / celery_config.py:

BROKER_URL = 'amqp://'
CELERY_RESULT_BACKEND = 'amqp://'

CELERY_ACCEPT_CONTENT = ['json']
CELERY_TASK_SERIALIZER = 'json'  # 'pickle' warning: can't use datetime in json
CELERY_RESULT_SERIALIZER = 'json'  # 'pickle' warning: can't use datetime in json
CELERY_TASK_RESULT_EXPIRES = 18000  # Results hang around for 5 hours

CELERYD_CONCURRENCY = 4

然后你可以把任務放在任何你需要的地方:

from task_mgr.task_mgr import celery
import time


@celery.task(bind=True)
def error_task(self):
    self.update_state(state='RUNNING')
    time.sleep(10)
    raise KeyError('im an error')


@celery.task(bind=True)
def long_task(self):
    self.update_state(state='RUNNING')
    time.sleep(20)
    return 'long task finished'


@celery.task(bind=True)
def task_with_status(self, wait):
    self.update_state(state='RUNNING')
    for i in range(5):
        time.sleep(wait)
        self.update_state(
            state='PROGRESS',
            meta={
                'current': i + 1,
                'total': 5,
                'status': 'progress',
                'host': self.request.hostname,
            }
        )
    time.sleep(wait)
    return 'finished with wait = ' + str(wait)

我還保留一個任務隊列來保存異步結果,以便我可以監視任務:

task_queue = []


def queue_task(task, *args):
    async_result = task.apply_async(args)
    task_queue.append(
        {
            'task_name':task.__name__,
            'task_args':args,
            'async_result':async_result
        }
    )
    return async_result


def get_tasks_info():
    tasks = []

    for task in task_queue:
        task_name = task['task_name']
        task_args = task['task_args']
        async_result = task['async_result']
        task_id = async_result.id
        task_state = async_result.state
        task_result_info = async_result.info
        task_result = async_result.result
        tasks.append(
            {
                'task_name': task_name,
                'task_args': task_args,
                'task_id': task_id,
                'task_state': task_state,
                'task_result.info': task_result_info,
                'task_result': task_result,
            }
        )

    return tasks

當然,在您需要的地方開始執行以下任務:

from webapp.app import app
from flask import url_for, render_template, redirect
from webapp import tasks
from task_mgr import task_mgr


@app.route('/start_all_tasks')
def start_all_tasks():
    task_mgr.queue_task(tasks.long_task)
    task_mgr.queue_task(tasks.error_task)
    for i in range(1, 9):
        task_mgr.queue_task(tasks.task_with_status, i * 2)

    return redirect(url_for('task_status'))


@app.route('/task_status')
def task_status():
    current_tasks = task_mgr.get_tasks_info()
    return render_template(
        'parse/task_status.html',
        tasks=current_tasks
    )

這就是它。 如果您需要任何幫助,請告訴我,盡管我的芹菜知識仍然相當有限。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM