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中metaclass元类的创建与使用
Jun 30 Python
python中将\\uxxxx转换为Unicode字符串的方法
Sep 06 Python
python中正则表达式 re.findall 用法
Oct 23 Python
python调用百度地图WEB服务API获取地点对应坐标值
Jan 16 Python
pthon贪吃蛇游戏详细代码
Jan 27 Python
浅析Python 实现一个自动化翻译和替换的工具
Apr 14 Python
在Pycharm中使用GitHub的方法步骤
Jun 13 Python
python自动化测试无法启动谷歌浏览器问题
Oct 10 Python
Python银行系统实战源码
Oct 25 Python
python 监控logcat关键字功能
Sep 04 Python
python如何绘制疫情图
Sep 16 Python
Python干货实战之八音符酱小游戏全过程详解
Oct 24 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中通过ADO调用Asscess数据库和COM程序
2006/10/09 PHP
php判断电脑访问、手机访问的例子
2014/05/10 PHP
PHP面向对象程序设计之接口用法
2014/08/20 PHP
thinkPHP简单实现多个子查询语句的方法
2016/12/05 PHP
PHP7下协程的实现方法详解
2017/12/17 PHP
详解php反序列化
2020/06/10 PHP
简单的邮箱登陆的提示效果类似于yahoo邮箱
2014/02/26 Javascript
jQuery瀑布流插件Wookmark使用实例
2014/04/02 Javascript
node.js操作mongodb学习小结
2015/04/25 Javascript
全面解析Bootstrap中form、navbar的使用方法
2016/05/30 Javascript
BOM系列第二篇之定时器requestAnimationFrame
2016/08/17 Javascript
利用vueJs实现图片轮播实例代码
2017/06/03 Javascript
js中document.write和document.writeln的区别
2018/03/11 Javascript
详解Vue文档中几个易忽视部分的剖析
2018/03/24 Javascript
video.js 实现视频只能后退不能快进的思路详解
2018/08/09 Javascript
微信小程序如何实现全局重新加载
2019/06/05 Javascript
Vue动态创建注册component的实例代码
2019/06/14 Javascript
[01:24:16]2018DOTA2亚洲邀请赛 4.6 全明星赛
2018/04/10 DOTA
python中的字典详细介绍
2014/09/18 Python
Python队列的定义与使用方法示例
2017/06/24 Python
Python爬虫获取整个站点中的所有外部链接代码示例
2017/12/26 Python
Python多线程threading和multiprocessing模块实例解析
2018/01/29 Python
Python简单读写Xls格式文档的方法示例
2018/08/17 Python
Python求两个圆的交点坐标或三个圆的交点坐标方法
2018/11/07 Python
Python 类方法和实例方法(@classmethod),静态方法(@staticmethod)原理与用法分析
2019/09/20 Python
python3读取autocad图形文件.py实例
2020/06/05 Python
Python爬虫实例——爬取美团美食数据
2020/07/15 Python
Python使用socket模块实现简单tcp通信
2020/08/18 Python
python自动化测试三部曲之request+django实现接口测试
2020/10/07 Python
Appium+Python实现简单的自动化登录测试的实现
2021/01/26 Python
CSS3实现圆角、阴影、透明效果并兼容各大浏览器
2014/08/08 HTML / CSS
大学生入党自我鉴定
2013/10/31 职场文书
电力公司个人求职信范文
2014/02/04 职场文书
体育节口号
2014/06/19 职场文书
经典搞笑版检讨书
2015/02/19 职场文书
老公婚前保证书
2015/02/28 职场文书