celery4+django2定时任务的实现代码


Posted in Python onDecember 23, 2018

网上有很多celery + django实现定时任务的教程,不过它们大多数是基于djcelery + celery3的;

或者是使用django_celery_beat配置较为繁琐的。

显然简洁而高效才是我们最终的追求,而celery4已经不需要额外插件即可与django结合实现定时任务了,原生的celery beat就可以很好的实现定时任务功能。

当然使用原生方案的同时有几点插件所带来的好处被我们放弃了:

  • 插件提供的定时任务管理将不在可用,当我们只需要任务定期执行而不需要人为调度的时候这点忽略不计。
  • 无法高效的管理或追踪定时任务,定时任务的跟踪其实交给日志更合理,但是对任务的修改就没有那么方便了,不过如果不需要经常变更/增减任务的话这点也在可接受范围内。

Celery定时任务配置

在进行配置前先来看看项目结构:

.
├── linux_news
│  ├── celery.py
│  ├── __init__.py
│  ├── settings.py
│  ├── urls.py
│  └── wsgi.py
├── manage.py
├── news
│  ├── admin.py
│  ├── apps.py
│  ├── __init__.py
│  ├── migrations
│  ├── models
│  ├── tasks.py
│  ├── tests.py
│  └── views
└── start-celery.sh

其中news是我们的app,用于从一些rss订阅源获取新闻信息,linux_news则是我们的project。我们需要关心的主要是 celery.py , settings.py , tasks.py 和 start-celery.sh

首先是celery.py,想让celery执行任务就必须实例化一个celery app,并把settings.py里的配置传入app:

import os
from celery import Celery

# set the default Django settings module for the 'celery' program.
os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'linux_news.settings')

app = Celery('linux_news')

# 'django.conf:settings'表示django,conf.settings也就是django项目的配置,celery会根据前面设置的环境变量自动查找并导入
# - namespace表示在settings.py中celery配置项的名字的统一前缀,这里是'CELERY_',配置项的名字也需要大写
app.config_from_object('django.conf:settings', namespace='CELERY')

# Load task modules from all registered Django app configs.
app.autodiscover_tasks()

配置就是这么简单,为了能在django里使用这个app,我们需要在__init__.py中导入它:

from .celery import app as celery_app

然后我们来看tasks.py,它应该位于你的app目录中,前面我们配置了自动发现,所以celery会自动找到这些tasks,我们的tasks将写在这一模块中,代码涉及了一些orm的使用,为了契合主题我做了些精简:

from linux_news.celery import celery_app as app
from .models import *
import time
import feedparser
import pytz
import html


@app.task(ignore_result=True)
def fetch_news(origin_name):
  """
  fetch all news from origin_name
  """
  origin = get_feeds_origin(origin_name)
  feeds = feedparser.parse(origin.feed_link)
  for item in feeds['entries']:
    entry = NewsEntry()
    entry.title = item.title
    entry.origin = origin
    entry.author = item.author
    entry.link = item.link
    # add timezone
    entry.publish_time = item.time.replace(tzinfo=pytz.utc)
    entry.summary = html.escape(item.summary)

    entry.save()


@app.task(ignore_result=True)
def fetch_all_news():
  """
  这是我们的定时任务
  fetch all origins' news to db
  """
  origins = NewsOrigin.objects.all()
  for origin in origins:
    fetch_news.delay(origin.origin_name)

tasks里是一些耗时操作,比如网络IO或者数据库读写,因为我们不关心任务的返回值,所以使用 @app.task(ignore_result=True) 将其屏蔽了。

任务配置完成后我们就要配置celery了,我们选择redis作为任务队列,我强烈建议在生产环境中使用rabbitmq或者redis作为任务队列或结果缓存后端,而不应该使用关系型数据库:

# redis
REDIS_PORT = 6379
REDIS_DB = 0
# 从环境变量中取得redis服务器地址
REDIS_HOST = os.environ.get('REDIS_ADDR', 'redis')

# celery settings
# 这两项必须设置,否则不能正常启动celery beat
CELERY_ENABLE_UTC = True
CELERY_TIMEZONE = TIME_ZONE
# 任务队列配置
CELERY_BROKER_URL = f'redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}'
CELERY_ACCEPT_CONTENT = ['application/json', ]
CELERY_RESULT_BACKEND = f'redis://{REDIS_HOST}:{REDIS_PORT}/{REDIS_DB}'
CELERY_TASK_SERIALIZER = 'json'

然后是我们的定时任务设置:

from celery.schedules import crontab
CELERY_BEAT_SCHEDULE={
    'fetch_news_every-1-hour': {
      'task': 'news.tasks.fetch_all_news',
      'schedule': crontab(minute=0, hour='*/1'),
    }
}

定时任务配置对象是一个dict,由任务名和配置项组成,主要配置想如下:

  • task:任务函数所在的模块,模块路径得写全,否则找不到将无法运行该任务
  • schedule:定时策略,一般使用 celery.schedules.crontab ,上面例子为每小时的0分执行一次任务,具体写法与linux的crontab类似可以参考文档说明
  • args:是个元组,给出任务需要的参数,如果不需要参数也可以不写进配置,就像例子中的一样
  • 其余配置项较少用,可以参考文档

至此,配置celery beat的部分就结束了。

启动celery beat

配置完成后只需要启动celery了。

启动之前配置一下环境。不要用root运行celery!不要用root运行celery!不要用root运行celery!重要的事情说三遍。

start-celery.sh:

export REDIS_ADDR=127.0.0.1

celery -A linux_news worker -l info -B -f /path/to/log

-A 表示app所在的目录,-B表示启动celery beat运行定时任务。

celery正常启动后就可以通过日志来查看任务是否正常运行了:

[2018-12-21 13:00:00,022: INFO/MainProcess] Received task: news.tasks.fetch_all_news[e4566ede-2cfa-4c19-b2f3-0c7d6c38690d] 
[2018-12-21 13:00:00,046: INFO/MainProcess] Received task: news.tasks.fetch_news[583e96dc-f508-49fa-a24a-331e0c07a86b] 
[2018-12-21 13:00:00,051: INFO/ForkPoolWorker-2] Task news.tasks.fetch_all_news[e4566ede-2cfa-4c19-b2f3-0c7d6c38690d] succeeded in 0.02503809699555859s: None
[2018-12-21 13:00:00,052: INFO/MainProcess] Received task: news.tasks.fetch_news[c61a3e55-dd3c-4d49-8d6d-ca9b1757db25] 
[2018-12-21 13:00:00,449: INFO/ForkPoolWorker-5] Task news.tasks.fetch_news[c61a3e55-dd3c-4d49-8d6d-ca9b1757db25] succeeded in 0.39487219898728654s: None
[2018-12-21 13:00:00,606: INFO/ForkPoolWorker-3] Task news.tasks.fetch_news[583e96dc-f508-49fa-a24a-331e0c07a86b] succeeded in 0.5523456179944333s: None

以上就是celery4运行定时任务的内容,希望对大家的学习有所帮助,也希望大家多多支持三水点靠木。

Python 相关文章推荐
Python获取linux主机ip的简单实现方法
Apr 18 Python
Python的requests网络编程包使用教程
Jul 11 Python
python django事务transaction源码分析详解
Mar 17 Python
django 将model转换为字典的方法示例
Oct 16 Python
Appium Python自动化测试之环境搭建的步骤
Jan 23 Python
python binascii 进制转换实例
Jun 12 Python
如何运行.ipynb文件的图文讲解
Jun 27 Python
Python各种扩展名区别点整理
Feb 27 Python
使用Pyhton 分析酒店针孔摄像头
Mar 04 Python
Django跨域资源共享问题(推荐)
Mar 09 Python
Python如何实现的二分查找算法
May 27 Python
python实现计算器简易版
Dec 17 Python
python3使用pandas获取股票数据的方法
Dec 22 #Python
Python实现将通信达.day文件读取为DataFrame
Dec 22 #Python
python3 cvs将数据读取为字典的方法
Dec 22 #Python
python将txt等文件中的数据读为numpy数组的方法
Dec 22 #Python
python将txt文件读取为字典的示例
Dec 22 #Python
Python3实现对列表按元组指定列进行排序的方法分析
Dec 22 #Python
python代码 输入数字使其反向输出的方法
Dec 22 #Python
You might like
如何突破PHP程序员的技术瓶颈分析
2011/07/17 PHP
php创建无限级树型菜单
2015/11/05 PHP
php设计模式之委托模式
2016/02/13 PHP
php生成word并下载代码实例
2019/03/15 PHP
PHP延迟静态绑定使用方法实例解析
2020/09/05 PHP
JavaScript 设计模式 富有表现力的Javascript(一)
2010/05/26 Javascript
javascript开发中因空格引发的错误
2010/11/08 Javascript
JavaScript快速检测浏览器对CSS3特性的支持情况
2012/09/26 Javascript
Android中的jQuery:AQuery简介
2014/05/06 Javascript
JS实现鼠标滑过链接改变网页背景颜色的方法
2015/10/20 Javascript
跟我学习javascript的prototype,getPrototypeOf和__proto__
2015/11/17 Javascript
jQuery中通过ajax调用webservice传递数组参数的问题实例详解
2016/05/20 Javascript
js实现的xml对象转json功能示例
2016/12/24 Javascript
BootStrap daterangepicker 双日历控件
2017/06/02 Javascript
Node.JS更改Windows注册表Regedit的方法小结
2017/08/18 Javascript
AngularJS中控制器函数的定义与使用方法示例
2017/10/10 Javascript
Vue页面刷新记住页面状态的实现
2019/12/27 Javascript
Python中optionParser模块的使用方法实例教程
2014/08/29 Python
Python使用迭代器捕获Generator返回值的方法
2017/04/05 Python
详解python如何在django中为用户模型添加自定义权限
2018/10/15 Python
Python面向对象进阶学习
2019/05/21 Python
详解Python中pyautogui库的最全使用方法
2020/04/01 Python
利用HTML5+CSS3实现3D转换效果实例详解
2017/05/02 HTML / CSS
前端使用canvas生成盲水印的加密解密的实现
2020/12/16 HTML / CSS
印尼最大的在线购物网站:MatahariMall.com
2016/08/26 全球购物
欧铁通票官方在线销售网站:Eurail.com
2017/10/14 全球购物
英国历史最悠久的DJ设备供应商:DJ Finance、DJ Warehouse、The DJ Shop
2019/09/04 全球购物
Bath & Body Works阿联酋:在线购买沐浴和身体用品
2021/02/27 全球购物
《三袋麦子》教学反思
2014/03/02 职场文书
大学军训感言300字
2014/03/09 职场文书
合作协议书范文
2014/08/20 职场文书
车贷收入证明范本
2014/09/14 职场文书
公务员年度考核个人总结
2015/02/12 职场文书
2015年图书馆个人工作总结
2015/05/26 职场文书
英语读书笔记
2015/07/02 职场文书
高中化学教学反思
2016/02/22 职场文书