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实现基于HTTP文件传输实例
Nov 08 Python
Python中Random和Math模块学习笔记
May 18 Python
Python实现文件复制删除
Apr 19 Python
python实现五子棋人机对战游戏
Mar 25 Python
python Web flask 视图内容和模板实现代码
Aug 23 Python
Python代码块及缓存机制原理详解
Dec 13 Python
keras 自定义loss model.add_loss的使用详解
Jun 22 Python
如何利用python检测图片是否包含二维码
Oct 15 Python
解决TensorFlow训练模型及保存数量限制的问题
Mar 03 Python
python中的装饰器该如何使用
Jun 18 Python
Django对接elasticsearch实现全文检索的示例代码
Aug 02 Python
用Python可视化新冠疫情数据
Jan 18 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
如何开发一个虚拟域名系统
2006/10/09 PHP
PHP连接SQLServer2005 的问题解决方法
2010/07/19 PHP
Smarty简单生成表单元素的方法示例
2016/05/23 PHP
浅谈php处理后端&接口访问超时的解决方法
2016/10/29 PHP
php使用高斯算法实现图片的模糊处理功能示例
2016/11/11 PHP
php实现通过soap调用.Net的WebService asmx文件
2017/02/27 PHP
phpstudy隐藏index.php的方法
2020/09/21 PHP
读jQuery之四(优雅的迭代)
2011/06/20 Javascript
js 剪切板的用法(clipboardData.setData)与js match函数介绍
2013/11/19 Javascript
js验证整数加保留小数点的简单实例
2013/12/02 Javascript
javascript 回调函数详解
2014/11/11 Javascript
javascript的push使用指南
2014/12/05 Javascript
充分发挥Node.js程序性能的一些方法介绍
2015/06/23 Javascript
JavaScript实现图片懒加载(Lazyload)
2016/11/28 Javascript
js学习总结之DOM2兼容处理顺序问题的解决方法
2017/07/27 Javascript
Vuejs2 + Webpack框架里,模拟下载的实例讲解
2018/09/05 Javascript
微信小程序点击顶部导航栏切换样式代码实例
2019/11/12 Javascript
微信小程序利用button控制条件标签的变量问题
2020/03/15 Javascript
jQuery zTree如何改变指定节点文本样式
2020/10/16 jQuery
python实现批量获取指定文件夹下的所有文件的厂商信息
2014/09/28 Python
Python爬虫实现抓取京东店铺信息及下载图片功能示例
2018/08/07 Python
python 获取url中的参数列表实例
2018/12/18 Python
Python去除字符串前后空格的几种方法
2019/03/04 Python
Django框架视图层URL映射与反向解析实例分析
2019/07/29 Python
python+jinja2实现接口数据批量生成工具
2019/08/28 Python
python tkinter图形界面代码统计工具(更新)
2019/09/18 Python
解决django-xadmin列表页filter关联对象搜索问题
2019/11/15 Python
Python 写了个新型冠状病毒疫情传播模拟程序
2020/02/14 Python
python 穷举指定长度的密码例子
2020/04/02 Python
Matlab中plot基本用法的具体使用
2020/07/17 Python
CSS3感应鼠标的背景闪烁和图片缩放动画效果
2014/05/14 HTML / CSS
皇家道尔顿官网:Royal Doulton
2017/12/06 全球购物
英国露营设备和户外服装购物网站:Simply Hike
2019/05/05 全球购物
石油工程专业毕业生求职信
2014/04/13 职场文书
关于运动会的广播稿50字
2014/10/17 职场文书
NoSQL优缺点与MongoDB数据库简介
2022/06/05 MongoDB