셀러리 빠른 학습 노트

목적

경기 침체 상황에서 우리는 기술 스택을 확장하고 경쟁력을 향상시킬 수 있습니다.

구조도

여기에 이미지 설명을 삽입하세요.
1. 브로커: 일반적으로 작업 대기열을 저장하는 Redis 또는 MQ
2. 작업자: 소비자
3. 백엔드: 결과 저장소 대기열(또한 Redis 또는 MQ이기도 함)
4. 작업: 개인적으로 생산자입니다.

설치하다

pip install celery

개인적으로 5.3.1을 직접 사용하는데, 시작하자마자 최신 버전이어서 함정이 생기고, 다른 분들의 이전 튜토리얼을 읽어보면 문제가 생길 것입니다.

첫 번째 구덩이

Traceback (most recent call last):
  File "C:\Python39\lib\site-packages\billiard\pool.py", line 362, in workloop
    result = (True, prepare_result(fun(*args, **kwargs)))
  File "C:\Python39\lib\site-packages\celery\app\trace.py", line 635, in fast_trace_task
    tasks, accept, hostname = _loc
ValueError: not enough values to unpack (expected 3, got 0)

이 오류는 your_func.delay() 작업을 통해 셀러리를 실행할 때 보고됩니다. GPT가 우회되는 것에 대해 문의했는데 나중에 인터넷에서 해결 방법을 찾았습니다. 아래 숙제를 복사해 두겠습니다.

해결하다

  • Windows 10 시스템.
    다른 분들의 설명에 따르면 win10에서 celery4.x를 실행할 때 이 문제가 발생한다고 합니다.해결 방법은 다음과 같습니다.원리는 알려져 있지 않습니다.먼저 이벤트렛을 설치하십시오.
pip install eventlet

그런 다음 작업자를 시작할 때 다음과 같이 매개변수를 추가합니다.

celery -A celery_tasks.main worker -l info -P eventlet

그러면 정상적으로 호출이 가능합니다

기본 사용법

my_task.py라는 Python 파일을 만듭니다.

import celery
import time

backend='redis://127.0.0.1:6379/1'
broker='redis://127.0.0.1:6379/2'
cel=celery.Celery('first_task',backend=backend,broker=broker)

@cel.task
def send_email(name):
    print("向%s发送邮件..."%name)
    time.sleep(5)
    print("向%s发送邮件完成"%name)
    return "ok"

@cel.task
def send_msg(name):
    print("向%s发送短信..."%name)
    time.sleep(5)
    print("向%s发送短信完成"%name)
    return "ok"

위의 my_task, cel, frist_task 네이밍을 보고 나중에 디버깅 정보 출력을 실행할 때 어떤 매개변수가 어떤 것인지 비교할 수 있도록 네이밍을 차별화해 보세요.

달리다

D:\代码\my_code\study\study_celery>celery -A my_task worker -l info -P eventlet

 -------------- celery@WINDOWS-3T5S0CL v5.1.2 (sun-harmonics)
--- ***** -----
-- ******* ---- Windows-10-10.0.10586-SP0 2023-07-02 20:24:05
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app:         first_task:0x2b9d54582e0
- ** ---------- .> transport:   redis://:**@120.79.235.7:6379/63
- ** ---------- .> results:     redis://:**@120.79.235.7:6379/63
- *** --- * --- .> concurrency: 8 (eventlet)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
 -------------- [queues]
                .> celery           exchange=celery(direct) key=celery


[tasks]
  . my_task.send_email
  . my_task.send_msg

[2023-07-02 20:24:06,312: INFO/MainProcess] Connected to redis://:**@120.79.235.7:6379/63
[2023-07-02 20:24:06,394: INFO/MainProcess] mingle: searching for neighbors
[2023-07-02 20:24:08,250: INFO/MainProcess] mingle: sync with 1 nodes
[2023-07-02 20:24:08,254: INFO/MainProcess] mingle: sync complete
[2023-07-02 20:24:08,368: INFO/MainProcess] pidbox: Connected to redis://:**@120.79.235.7:6379/63.
[2023-07-02 20:24:08,500: INFO/MainProcess] celery@WINDOWS-3T5S0CL ready.

위의 내용은 각 이름이 무엇을 나타내는지 쉽게 구별할 수 있도록 너무 많은 다른 이름을 만들라는 메시지를 표시합니다.

  • celery -A my_task 작업자 -l info -P
    eventlet 시작 명령에서 my_task는 파일 이름입니다. 시작 명령에 .py를 포함하지 마세요.

  • app: first_task:0x2b9d54582e0
    앱 이름은 celery.Celery가 앱을 생성할 때 전달되는 첫 번째 매개변수입니다.

  • Transport: redis://: @120.79.235.7:6379/63
    results: redis://:
    @120.79.235.7:6379/63
    더 많은 프로젝트, 테스트 및 공식 환경이 있는 경우 중간 Redis 및 결과 Redis를 기억하세요. 시작할 때 자세히 확인하려면

  • [tasks]
    . my_task.send_email
    . my_task.send_msg
    여기에서 셀러리 앱에 어떤 작업이 있는지 명확하게 확인할 수 있습니다.

  • celery@WINDOWS-3T5S0CL Ready
    이 메시지를 보면 redis가 정상적으로 실행되고 있는 것입니다.

시작 정보를 과소평가하지 마시고, 시작할 때마다 내부 정보를 확인하시기 바랍니다.

셀러리 앱을 실행해 보세요

먼저 producer_task.py 파일을 생성하십시오:

from my_task import send_email, send_msg

email_result = send_email.delay("hello")
print(email_result.id)

msg_result = send_msg.delay("world")
print(msg_result.id)

위 코드를 실행한다는 것은 실행 중인 셀러리에게 두 개의 실행 명령(send_msg, send_email)을 보내는 것을 의미하며, 지연 시 직접 전달되는 매개변수는 send_msg의 매개변수이다.

함정을 밟아라

여기에 또 다른 함정이 있습니다. 브로커와 백엔드가 동일한 Redis에 있는 경우 두 번의 지연이 발생합니다. 하나만 실행되며 문제를 찾을 수 없습니다. 그런 다음 두 번의 지연으로 교체하면 됩니다. 나중에 문제의 근본 원인을 찾을 수 있으므로 지금 학습 진행을 계획하지 마십시오.

실행 결과 보기

여기에 이미지 설명을 삽입하세요.여기에 이미지 설명을 삽입하세요.

모든 실행 결과는 백엔드의 redis에서 확인할 수 있으며, 성공과 실패는 문자열 형태로 저장됩니다. DB 루트 디렉터리에 직접 저장

실행 결과 가져오기

# 成功结果
async_succ_result = AsyncResult(id="23c7ebfd-5bf6-4f83-b7c8-9c870b168d17", app=cel)
# 失败结果
async_fail_result = AsyncResult(id="923360d1-caa4-41ca-9887-3bc404ff0803", app=cel)
# 判断是否成功
success_flag1 = async_succ_result.successful()
success_flag2 = async_fail_result.successful()
# 判断是否失败
failure_flag1 = async_succ_result.failed()
failure_flag2 = async_fail_result.failed()
# 获取结果,如果是成功,则返回之前函数里的return
result = async_succ_result.get()
# 获取结果,如果是失败,则会报异常
try:
    result = async_fail_result.get()
except Exception as e:
    print(e)

운영상태

# 运行结果状态
if async_succ_result.status == 'PENDING':
    print('任务等待中被执行')
elif async_succ_result.status == 'RETRY':
    print('任务异常后正在重试')
elif async_succ_result.status == 'STARTED':
    print('任务已经开始被执行')
elif async_succ_result.status == 'FAILURE':
    print('任务执行失败')
elif async_succ_result.status == 'SUCCESS':
    print('任务执行成功')

함수의 설명에는 다음 5가지 상태만 있습니다.

결과 삭제

async_succ_result.forget()

결과가 삭제되면 검색이 중단됩니다.

멀티태스킹 구조

  • 많은 작업을 수행해야 할 경우 작업을 구조적으로 계층화해야 하며, 이때 유지 관리를 위해 여러 파일을 구분해야 합니다.
    여기에 이미지 설명을 삽입하세요.

멀티태스킹 루트 디렉터리로 my_multi_tasks라는 새 디렉터리를 만듭니다.

  • celery.py 파일 생성
import celery

backend='redis://127.0.0.1:6379/1'
broker='redis://127.0.0.1:6379/2'
second_cel = celery.Celery(
    'second_tasks',
    backend=backend,
    broker=broker,
    include={
    
    
        'my_multi_tasks.my_task_01',
        'my_multi_tasks.my_task_02'
    }
)

여기서 파일 이름은 celery여야 합니다. celery.exe 컨트롤러가 명령을 실행할 때 프로젝트에서 셀러리 파일을 감지하여 멀티태스킹 구조를 구성하기 때문입니다. 이름이 celery가 아니면 다음과 같이 오류가 보고됩니다.

D:\代码\my_code\study\study_celery>celery -A my_multi_tasks worker -l info -P eventlet
Usage: celery [OPTIONS] COMMAND [ARGS]...

Error: Invalid value for '-A' / '--app':
Unable to load celery application.
Module 'my_multi_tasks' has no attribute 'celery'

모듈 'my_multi_tasks'에는 'celery' 속성이 없습니다. 이는 my_multi_tasks에 celery 속성이 없음을 나타냅니다. 기본 프로그램은 .celery입니다.

  • my_task_01.py 파일 생성
import time
from my_multi_tasks.elery import second_cel

@second_cel.task
def second_send_email(name):
    print(f"向{name}发送邮件".center(30, '1'))
    time.sleep(5)
    print(f"向{name}发送邮件完成".center(30, '1'))
    return "ok"
  • my_task_02.py 파일 생성
import time
from my_multi_tasks.elery import second_cel

@second_cel.task
def second_send_msg(name):
    print(f"向{name}发送短信".center(30, '2'))
    time.sleep(5)
    print(f"向{name}发送短信完成".center(30, '2'))
    return "ok"

이제 task01과 task02에 각각 send_email과 send_msg를 넣고, 함수 앞에 다중 작업 구조의 셀러리를 추가하는 것을 잊지 마세요.

  • producer_task_second.py 파일 생성
from my_multi_tasks.my_task_01 import second_send_email
from my_multi_tasks.my_task_02 import second_send_msg

email_result = second_send_email.delay('second_hello')
msg_result = second_send_msg.delay('second_world')
  • celery -A my_multi_tasks Worker -l info -P eventlet 명령을 실행하여
    셀러리를 시작한 후 producer_task_second.py 파일을 사용하여 작업을 보냅니다. 작업 실행 과정을 볼 수 있습니다.

예약 된 일들

태스크 구조는 여전히 위의 다중 태스크 구조를 직접 복사한 태스크 본문입니다. 예약된 작업을 위해 p에 생성 파일을 하나 더 추가하는 방법에 대한 설명

from datetime import datetime
from my_multi_tasks.my_task_01 import second_send_email
from my_multi_tasks.my_task_02 import second_send_msg

# 指定时间发送
time_temp = datetime(2023, 7, 4, 6, 19, 00)
time_temp_utc = datetime.utcfromtimestamp(time_temp.timestamp())
result = second_send_email.apply_async(args=['kola', ], eta=time_temp_utc)
print(result.id)

# 延迟发送
from datetime import timedelta
time_now = datetime.now()
time_now_utc = datetime.utcfromtimestamp(time_now.timestamp())
time_now_utc_new = time_now_utc + timedelta(seconds=20)
result2 = second_send_msg.apply_async(args=['cat', ], eta=time_now_utc_new)
print(result2.id)
  • 참고:
    1. Celery의 예약된 작업은 기본적으로 국제 표준 UTC를 기준으로 하므로 중국 시간의 경우 UTC 변환이 필요합니다.
    2. 위 명령문을 실행한 후 스크립트가 종료되고 작업이 대기열에 추가되었습니다. 대기 시간이
    3이 된 후 실행. args에 전달된 매개변수에 주의하세요. ['kola', ]입니다. 쉼표가 있는데 이는 튜플이 전달되었다는 의미입니다.

구성 정보 및 비트를 통해 예약된 작업을 시작합니다.

beat는 셀러리의 매우 중요한 생산자입니다. 워커와 마찬가지로 스크립트 서비스입니다. 시작한 후 계속 실행되는 스크립트 프로그램입니다. 이제 구성해 보겠습니다.

import celery
from celery.schedules import crontab


backend='redis://127.0.0.1:6379/1'
broker='redis://127.0.0.1:6379/2'
second_cel = celery.Celery(
    'second_tasks',
    backend=backend,
    broker=broker,
    include={
    
    
        'my_multi_tasks.my_task_01',
        'my_multi_tasks.my_task_02'
    }
)


# 设置定时任务的执行时间的时区,改为中国,关闭utc
second_cel.conf.timezone = 'Asia/Shanghai'
second_cel.conf.enable_utc = False


# 发送任务的调度器
second_cel.conf.beat_schedule = {
    
    
    # 随意命名
    'add-task-every-1-minute': {
    
    
        # 传参
        'args': ('张三',),
        # 执行函数的路径,指定second_send_email函数
        'task': 'my_multi_tasks.my_task_01.second_send_email',
        # 调度时间
        # 'schedule': 10.0,                     # 每几秒,执行一次
        # 'schedule': timedelta(seconds=6),     # 每几秒,执行一次,但timedelta更丰富,比如day,hour
        'schedule': crontab(minute="*/1"),    # 每一分钟,执行一次
    },
    'add-task-birthday': {
    
    
        'args': ('李四',),
        'task': 'my_multi_tasks.my_task_02.second_send_msg',
        # 每年411号,842分执行
        'schedule': crontab(minute=10, hour=5, day_of_month=5, month_of_year=7),
    },
}

Celery는 작업 실행을 위한 기본 시간대를 직접 수정하는 것을 지원합니다. second_cel.conf.timezone은
구성을 통해 예약된 작업 목록을 생성합니다. second_cel.conf.beat_schedule

  • 시작 명령: celery -A my_multi_tasks beat -l info
    -P는 소비자의 실행 프로그램을 지정하므로 여기에 -P 이벤트렛을 추가할 필요가 없습니다. 이 프로듀서님, 그러니까 필요 없어요.

실행 및 관찰을 통해 생산자 비트와 소비자 작업자가 완전히 분리되어 있음을 확인할 수 있습니다. beat도 프로그램이며, 명령줄을 통해 시작된 후 구성 테이블에 설정된 시간에 따라 미들웨어 브로커의 주요 셀러리로 예약된 작업을 전달합니다. 다음은 예시입니다

{
    
    
	"body": "W1siXHU2NzRlXHU1NmRiIl0sIHt9LCB7ImNhbGxiYWNrcyI6IG51bGwsICJlcnJiYWNrcyI6IG51bGwsICJjaGFpbiI6IG51bGwsICJjaG9yZCI6IG51bGx9XQ==",
	"content-encoding": "utf-8",
	"content-type": "application/json",
	"headers": {
    
    
		"lang": "py",
		"task": "my_multi_tasks.my_task_02.second_send_msg",
		"id": "1dce9df1-da1e-4c4e-ac6b-be170b815400",
		"shadow": null,
		"eta": null,
		"expires": null,
		"group": null,
		"group_index": null,
		"retries": 0,
		"timelimit": [null, null],
		"root_id": "1dce9df1-da1e-4c4e-ac6b-be170b815400",
		"parent_id": null,
		"argsrepr": "['\u674e\u56db']",
		"kwargsrepr": "{}",
		"origin": "gen12600@WINDOWS-3T5S0CL",
		"ignore_result": false
	},
	"properties": {
    
    
		"correlation_id": "1dce9df1-da1e-4c4e-ac6b-be170b815400",
		"reply_to": "3f3250fb-6ed4-3d13-83db-a7d8e30c8ee9",
		"delivery_mode": 2,
		"delivery_info": {
    
    
			"exchange": "",
			"routing_key": "celery"
		},
		"priority": 0,
		"body_encoding": "base64",
		"delivery_tag": "88d2a3dd-5612-4ef7-ae36-0d2484b9a468"
	}
}

관찰하는데 의미가 있는 매개변수 값이 두 개밖에 없는 것 같은데, 하나는 작업 함수이고 다른 하나는 매개변수
"task": "my_multi_tasks.my_task_02.second_send_msg",
"argsrepr": "['\u674e \u56db']",

  • 비트가 시작된 후, 시간 내에 작업이 소모되지 않으면 점점 더 많은 작업이 쌓이게 되니 주의하세요. 작업자가 시작되면 이러한 모든 작업이 실행됩니다. 일부 만료 비실행 메커니즘이 필요할 수 있습니다.

Django의 셀러리 애플리케이션

여기에 이미지 설명을 삽입하세요.
새로운 Django 프로젝트를 생성하고, 추가 설정의 애플리케이션 이름에 app01을 입력하면 프로젝트 생성 시 앱이 생성됩니다.

여기에 이미지 설명을 삽입하세요.app01의 보기를 가리키는 URL에 테스트 경로를 생성한
다음 app01의 보기 보기 기능에 테스트 기능을 추가합니다. 웹사이트가 127.0.0.1/test 페이지에 액세스하는지 테스트하고 정상적으로 반환되는지 확인하면 됩니다.

  • 그런 다음 Django 프로젝트의 루트 디렉터리 아래에 my_celery 폴더를 만들어 위와 같이 셀러리 디렉터리
    여기에 이미지 설명을 삽입하세요.
    의 구성을 저장합니다. 이메일 작업, SMS 작업, config는 구성 파일, main은 기본 프로그램입니다.
  • config.py(구성 파일, 여기서 Broker_url 및 result_backend의 두 변수 이름에 특히 주의하세요. 잘못되어서는 안 됩니다. )
broker_url = 'redis://127.0.0.1:6379/15'
result_backend = 'redis://127.0.0.1:6379/14'
  • task.py (태스크 파일, 셀러리 태스크는 반드시 task.py 파일에 작성해야 하며, 다른 파일명은 인식되지 않습니다. )
import time
import logging
from my_celery.main import app
log = logging.getLogger("django")

@app.task  # name表示设置任务的名称,如果不填写,则默认使用函数名做为任务名
def send_sms(mobile):
    """发送短信"""
    print("向手机号%s发送短信成功!"%mobile)
    time.sleep(5)
    return "send_sms OK"

@app.task  # name表示设置任务的名称,如果不填写,则默认使用函数名做为任务名
def send_sms2(mobile):
    print("向手机号%s发送短信成功!" % mobile)
    time.sleep(5)
    return "send_sms2 OK"
  • main.py(메인 프로그램, 셀러리 앱 생성 및 Django 구성 파일 로드)
import os
from celery import Celery

# 创建celery的实例对象,做解耦,不在这里传参broker和backend,通过配置文件进行设置
app = Celery('my_django_celery')

# 把celery和Django进行结合,识别和加载Django的配置文件,注意这里是在环境中加入Django的配置
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'celeryPros.settings.dev')

# 通过app对象加载配置,把config.py里面的配置读到celery里面去
app.config_from_object('my_celery.config')

# 加载任务,注意!默认会去目录底下的tasks.py文件里面找,所以tasks.py这个文件命名有特殊意义
app.autodiscover_tasks([
    'my_celery.my_email',
    'my_celery.my_sms',
])

# 启动Celery的命令
# 强烈建议切换目录到mycelery根目录下启动
# celery -A my_celery.main worker --loglevel=info
  • 시작 명령: celery -A my_celery.main Worker --loglevel=info
    여기서 경로는 celery 폴더 외부에 있어야 한다는 점에 유의한 후 명령을 실행합니다. my_celery.main을 통해 경로를 찾을 수 있습니다.

위 구성이 완료된 후 Django app01 프로젝트의 views.py 함수로 돌아가 작업을 트리거합니다.

from django.shortcuts import render, HttpResponse
from my_celery.my_sms.tasks import send_sms
from my_celery.my_sms.tasks import send_sms2
from my_celery.my_email.tasks import send_email
from my_celery.my_email.tasks import send_email2

# Create your views here.

def test(request):
    # 异步任务
    # 1. 声明一个和celery一模一样的任务函数,但是我们可以导包来解决
    # send_sms.delay("110")
    # send_sms2.delay("119")
    # # send_sms.delay()        #如果调用的任务函数没有参数,则不需要填写任何内容

    # 定时任务
    from datetime import timedelta, datetime
    time_now = datetime.now()
    time_now_utc = datetime.utcfromtimestamp(time_now.timestamp())
    time_now_utc_new = time_now_utc + timedelta(seconds=20)
    send_email.apply_async(args=['cat', ], eta=time_now_utc_new)

    return HttpResponse('ok')

Django 프로젝트를 시작한 다음 브라우저에서 http://127.0.0.1:8000/test/ 경로에 액세스하여 vies 보기 기능에 액세스하여 작업을 트리거합니다.

Supongo que te gusta

Origin blog.csdn.net/weixin_43651674/article/details/131504406
Recomendado
Clasificación