qq环境说明:
总体描述:
主机器A:django、django-celery-beat、celery 负责分发任务
从机器B:celery 做worker机器,监听任务队列,接收主机发送的任务消息,执行相应的任务
borker:此次用redis,可用任意一台机器做broker,A或B或其他都可以
主机器A的目录结构:若不使用django服务,urls.py views.py可不要
(1)__init__.py
from celerytest.celery import app as celery_app
# 使得django启动时加载celery的app
__all__ = ('celery_app',)
(2)celery.py 创建celery实例
'''
通过from future import absolute_import来声明使用绝对引用,这样是为了下面的from celery import Celery引用的是系统celery模块,而不是我们自己创建的celery.py
'''
from __future__ import absolute_import, unicode_literals
from celery import Celery
import os
import celerytest.celeryconfig
#from django.utils import timezone
# 为celery指定DJANGO_SETTINGS_MODULE环境变量
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'celerytest.settings')
# 创建celery的实例app,要在指定DJANGO_SETTINGS_MODULE环境变量之后
app = Celery('tasks')
# app = Celery('tasks', broker=CELERY_BROKER_URL, backend=CELERY_RESULT_BACKEND)
app.config_from_object('celerytest.celeryconfig', namespace='CELERY') # 命名空间 namespace='CELERY'定义所有与celery相关的配置的键名要以'CELERY_'为前缀
# app.now = timezone.now
# Load task modules from all registered Django app configs.
# 使用app.autodiscover_tasks()来自动发现django应用中的所有tasks模块
# app.autodiscover_tasks()
(3)celeryconfig.py celery的专用配置文件
在django的setting中,设置django的使用时区,与之对应
#from datetime import timedelta
#from kombu import Exchange, Queue
# 关闭时区
# enable_utc = False
timezone = 'Asia/Shanghai'
# DJANGO_CELERY_BEAT_TZ_AWARE = False
broker_url = 'redis://10.60.49.136:6379/1'
# 指定任务接受的序列化类型
accept_content = ['json']
result_backend = 'redis://10.60.49.136:6379/2'
# 指定任务序列化方式
task_serializer = 'json'
# 指定结果序列化的方式
result_serializer = 'json'
# 任务过期时间,celery任务执行结果的超时时间
# CELERY_TASK_RESULT_EXPIRES = 60 * 30
# 默认队列,如果一个消息不符合其他的队列就会放在默认队列里面
task_default_queue = 'default' # 更改默认队列的名称
task_default_exchange = 'default'
task_default_routing_key = 'default'
# 异步任务
imports = ('demo.tasks',
'demo.task2',
)
# 以下代码为写死的定时任务,如果不需要动态添加任务等操作,将以下代码释放来用即可
# # 设置详细的队列
# task_queues = {
# Queue('default', exchange=Exchange('default'), routing_key='default'),
# Queue('priority_high', exchange=Exchange('priority_high', type='direct'), routing_key='priority_high'),
# Queue('priority_low', exchange=Exchange('priority_low'), routing_key='priority_low'),
# }
# # 任务进队列
# task_routes = {
# 'demo.tasks.*': {'queue': 'priority_high', 'routing_key': 'priority_high'},
# 'demo.task2.*': {'queue': 'priority_low', 'routing_key': 'priority_low'},
# }
# 启用celery的定时任务需要设置celerybeat_schedule,celery的定时任务都由celery beat来进行调度。
# CELERY_CELERYBEAT_SCHEDULE = {
# 'add-every-30-seconds': {
# 'task': 'com.fingard.tasks.ebank.control.EBankTask.start',
# 'schedule': timedelta(seconds=10), # 每 30 秒执行一次
# 'args': ('PSB', 5, 8) # 任务函数参数
# }
# }
#
(4) task.py 定义任务
如以下my_task3,在主机器上,不需要编写具体的任务内容,worker机器上才需要有具体的任务内容,如my_task2
import time
# from celery import shared_task
from celerytest.celery import app
@app.task # 通过加上装饰器,将其注册到broker的队列中
def my_task1(x, y):
print("任务1开始执行...")
time.sleep(5)
print("任务1执行结束...")
return x + y
@app.task
def my_task2():
print("任务2开始执行...")
time.sleep(5)
print("任务2执行结束...")
return 2
@app.task
def my_task3():
pass
(5)main.py 发送任务
from demo import tasks
result1 = tasks.my_task1.delay(2, 8)
result2 = tasks.my_task2.delay()
# my_task1.apply_async(queue=)
# print(result1.get())
(1)将以上代码copy到从机B上,其中task.py中需要定义完整的任务,不能pass。打开终端,运行以下命令开启worker,
celery -A celerytest worker -l info -P eventlet
(2)主机器开启任务调度器,打开终端,输入以下命令:
释放celeryconfig.py里的定时任务代码,可执行写死的定时任务
celery beat -A celery_app -l info --pidfile=
注:--pidfile= 这个一定要加上,不然会报ERROR: Pidfile (celerybeat.pid) already exists.
(3)运行main.py文件,发送即时任务
(1)将django-celery-beat注册到apps中
(2)在setting.py中增加定时任务的配置
(3)由于定时器信息存储在数据库中,需要先生成对应的表,对django-celery-beat执行迁移操作,创建对应的表。
python manage.py migrate
(4)管理定时任务:
首先创建后台管理员账号:
python manage.py createsuperuser
登录管理后台admin:
其中Crontabs用于定时某个具体时间执行某个任务的时间,Intervals用于每隔多久执行任务的事件,具体任务的执行在Periodic tasks表中创建。
我们要创建每隔5秒执行某个任务,所以在Intervals表名后面点击Add按钮:
然后在Periodic tasks表名后面,点击Add按钮,添加任务:
操作django-celery-beat生成的数据表,二次开发界面,此处附上增删改查的方法
import os, django, pytz, json
os.environ.setdefault("DJANGO_SETTINGS_MODULE", "com.fingard.celerytest.settings")
django.setup()
from django_celery_beat import models as celery_models
def task_add(task_name, task_queue, task_kwargs, task_class, task_cron):
'''
任务添加
:param task_name: 任务名称
:param task_queue: 任务队列
:param task_kwargs: 任务传递参数
:param task_class: 任务执行类
:param task_cron: 任务定时的表达式
:return:
'''
# 获取crontab,没有就创建
schedule, _ = celery_models.CrontabSchedule.objects.get_or_create(**task_cron, timezone=pytz.timezone('Asia/Shanghai'))
task = celery_models.PeriodicTask.objects.create(crontab=schedule, name=task_name, task=task_class)
task.queue = task_queue
task.exchange = task_queue
task.routing_key = task_queue
task.kwargs = json.dumps(task_kwargs)
task.enabled = True
task.save()
celery_models.PeriodicTasks.changed(task)
return task.id
def task_update(task_id, task_name, task_queue, task_cron):
'''
修改任务
:param task_id: 需要修改的任务的id
:param task_name: 修改后的任务名称,若需要修改,以字符串形式传递
:param task_queue: 修改后的任务队列名称,若需要修改,以字符串形式传递
:param task_cron: 修改后的时间表
:return:
'''
per_task = celery_models.PeriodicTask.objects.get(id=task_id)
if task_name and task_name != per_task.name:
per_task.name = task_name
if task_queue and task_queue != per_task.queue:
per_task.queue = task_queue
per_task.exchange = task_queue
per_task.routing_key = task_queue
if task_cron and task_cron != per_task.crontab:
schedule = celery_models.CrontabSchedule.objects.create(**task_cron, timezone=pytz.timezone('Asia/Shanghai'))
per_task.crontab = schedule
per_task.save()
celery_models.PeriodicTasks.changed(per_task)
return per_task.name, per_task.queue, per_task.args, per_task.task, per_task.crontab
def task_del(task_ids):
'''
删除任务
:param task_ids: 任务id的list
:return:
'''
count = 0
for task_id in task_ids:
# 暂停执行周期性任务
task_query = celery_models.PeriodicTask.objects.get(id=task_id)
task_query.enabled = False
task_query.save()
# 删除任务
task_query.delete()
count += 1
celery_models.PeriodicTasks.update_changed()
return count
def task_list(task_name, task_queue):
'''
任务查询
:param task_name: 任务名称
:param task_queue: 任务队列
:return: task_name任务名称、task_queue任务队列、task_args任务参数、task_class任务执行类、task_cron任务定时的表达式
'''
# 查询目前满足条件的所有周期性任务
per_task = celery_models.PeriodicTask.objects.get(name=task_name, queue=task_queue)
data = {
"task_name": per_task.name,
"task_queue": per_task.queue,
"task_kwargs": per_task.kwargs,
"task_class": per_task.task,
"task_cron": per_task.crontab,
}
return data
def queue_update(queue_name_pre, queue_name_cur):
'''
更改任务的队列
:param queue_name_pre: 要改的队列名称
:param queue_name_cur: 改变后的队列名
:return:
'''
all_tasks = celery_models.PeriodicTask.objects.filter(queue=queue_name_pre)
all_tasks_ids = [per_task.id for per_task in all_tasks]
for task_id in all_tasks_ids:
task_query = celery_models.PeriodicTask.objects.get(id=task_id)
task_query.queue = queue_name_cur
task_query.exchange = queue_name_cur
task_query.routing_key = queue_name_cur
task_query.save()
celery_models.PeriodicTasks.update_changed()
all_tasks = celery_models.PeriodicTask.objects.filter(queue=queue_name_cur)
return all_tasks
(5)启动
从机启动worker:
celery -A celerytest worker -l info -Q 监听的队列名 -P eventlet
-Q 设置worker监听的队列名,不设置的话监听默认队列
主机器启动beat,分发任务
celery -A celerytest beat -l info --scheduler django_celery_beat.schedulers:DatabaseScheduler --pidfile=
启动flower可进行监控:在http://localhost:5555查看
celery -A celerytest flower
暂时写到这里。。。。待完善。