您现在的位置是: 网站首页 >服务部署 服务部署
使用Celery+Redis实现异步任务,supervisor守护进程运行
admin2018年11月30日 17:06 【Django | Linux | Python 】 1314人已围观
# Celery介绍 在程序运行过程中,经常会遇到一些耗时耗资源的任务,为了避免这些任务阻塞主进程的运行,我们会采用多线程或异步任务去处理。比如在Web中需要对新注册的用户发一封激活邮件来验证账户,而发邮件本身是一个IO阻塞式任务,如果把它直接放到应用中,就会阻塞主程序的运行,用户需要等待邮件发送完成后才能进行下一步操作。一种解决办法是为每个发邮件任务新开一个线程去执行,当线程很多时这也不是很好的解决办法;更好的方式是在业务逻辑中触发一个发邮件的异步任务,把待发送的任务都发往任务队列,主程序可以继续往下运行。 Celery是一个强大的分布式任务队列,他可以让任务的执行完全脱离主程序,甚至可以把任务分配到其他主机上运行。我们通常使用它来实现异步任务(async task)和定时任务(crontab)。它的架构组成如下图: ![BLOG_20181201_221005_33](/media/blog/images/2018/12/BLOG_20181201_221005_33.png "博客图集BLOG_20181201_221005_33.png") 可以看到, Celery 主要包含以下几个模块: - 任务模块 充当任务生产者,包含异步任务和定时任务。其中,异步任务通常在业务逻辑中被触发并发往任务队列,而定时任务由 Celery Beat 进程周期性地将任务发往任务队列。 - 消息中间件 Broker Broker ,即为任务调度队列,接收任务生产者发来的消息,将任务存入队列。 Celery 本身不提供队列服务,官方推荐使用 RabbitMQ 和 Redis 等。 - 任务执行单元 Worker 充当任务消费者。Worker 是执行任务的处理单元,它实时监控消息队列,获取队列中调度的任务,并执行它。broker通知worker队列中有任务,worker去队列中取出任务执行,每一个worker就是一个进程 - 任务结果存储 Backend Backend 用于存储任务的执行结果,以供查询。同消息中间件一样,存储也可使用 RabbitMQ, Redis 和 MongoDB 等。 # 使用Celery+Redis实现异步任务,supervisor守护进程运行 http://docs.celeryproject.org/en/latest/django/first-steps-with-django.html#using-celery-with-django *Django2.1.3+Celery4.2.1+Redis2.10.6(如果用3的redis会报错:AttributeError: 'float' object has no attribute 'items')+Redis-Server* ## settings.py中配置 ```python # Celery+Redis实现异步任务,首先需要pip install celery # 配置Broker # BROKER_URL = 'redis://localhost:63079/3' # 无密码情况 BROKER_URL = 'redis://:password@127.0.0.1:63079/3' BROKER_TRANSPORT = 'redis' CELERY_ACCEPT_CONTENT = ['pickle', 'json'] # 启用实际使用的序列化程序,不加似乎会出现警告 CELERYD_MAX_TASKS_PER_CHILD = 40 # 设置每个worker执行了多少任务就会死掉,长时间运行Celery有可能发生内存泄露 ``` ## 创建celery.py模块 项目中和settings.py同级目录下创建celery.py模块,用于定义Celery实例 然后编辑 ```python # StarMeow/StarMeow/celery.py from __future__ import absolute_import, unicode_literals import os import django from celery import Celery, platforms from django.conf import settings # 为“celery”程序设置默认的Django settings模块。 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'StarMeow.settings') django.setup() # 使用settings.py中的相关配置,不加这个,就会提示app参数不够 # 如果不加django.setup(),下面就需要使用app = Celery('StarMeow', broker='...broker配置地址...') app = Celery('StarMeow') # 在这里使用字符串意味着worker不必序列化子进程的配置对象。 # namespace ='CELERY'表示所有与celery相关的配置键应该有一个`CELERY_`前缀, # 例如settings.py中的CELERY_BROKER_URL,这个就需要加CELERY_前缀,不定义namespace,则不加前缀。 app.config_from_object('django.conf:settings', namespace='CELERY') # 从所有注册的Django app configs加载任务模块。 # app.autodiscover_tasks() app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) # 也可以使用这行,只添加INSTALLED_APPS中的app platforms.C_FORCE_ROOT = True # Linux在root用户下不能启动,需要添加这一行 @app.task(bind=True) def debug_task(self): print('Request: {0!r}'.format(self.request)) ``` 分析: - `from __future__ import absolute_import`:从绝对路径中导入的celery.py模块不会与库冲突 - `os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'StarMeow.settings')`:为celery命令行程序设置默认的`DJANGO_SETTINGS_MODULE `环境变量 - `app.autodiscover_tasks()`:可重用应用程序的常见实践是在单独的任务中定义所有tasks.py模块,Celery有一种自动发现这些模块的方法。 ## 导入Celery应用程序 ```python # StarMeow/StarMeow/__init__.py from __future__ import absolute_import, unicode_literals # 然后需要在StarMeow/StarMeow/__init__.py模块中导入这个应用程序。 # 这样可以确保Django启动时加载应用程序,以便@shared_task装饰器使用它 from .celery import app as celery_app __all__ = ('celery_app',) ``` ## 应用下创建tasks.py 使用`@shared_task`装饰器 编写的任务可能存在于可重用的应用程序中,而可重用的应用程序不能依赖于项目本身,因此也不能直接导入应用程序实例。 `@shared_task`装饰器允许您创建任务,而不需要任何具体的应用程序实例 在blog应用下创建tasks.py文件,写入 ```python from __future__ import absolute_import, unicode_literals from celery import shared_task @shared_task def print_info(): print('正在进入blog应用的tasks.py') return None # 可以不返回 ``` 另一种运行方式 ```python from StarMeow.celery import app @app.task def print_info(): print('正在进入blog应用的tasks.py') return None # 可以不返回 ``` settings.py增加这个参数,Celery就会忽略全部调度机制,立即调用你的代码。 ``` CELERY_ALWAYS_EAGER = True ``` 这样`print_info()`和`print_info.delay()`效果一样 ## 启动celery 测试方法: https://github.com/celery/celery/tree/master/examples/django/ 进入项目所在目录,启动虚拟环境,启动worker ### Windows下启动 ```dos C:\Users\LR>cd E:\Sync\OneDrive\PycharmProjects\StarMeow C:\Users\LR>E: E:\Sync\OneDrive\PycharmProjects\StarMeow>workon StarMeow (StarMeow) E:\Sync\OneDrive\PycharmProjects\StarMeow>celery -A StarMeow worker -l info ``` ![BLOG_20181130_170720_95](/media/blog/images/2018/11/BLOG_20181130_170720_95.png "博客图集BLOG_20181130_170720_95.png") 视图里面添加运行 ```python class IndexView(View): def get(self, request, **kwargs): print_info.delay() # 省略 ``` 然后访问 ![BLOG_20181130_170729_64](/media/blog/images/2018/11/BLOG_20181130_170729_64.png "博客图集BLOG_20181130_170729_64.png") 这个问题网上都有解决方案,使用一个最简单的方案,更改运行方式,访问就正常了 ```bat celery -A StarMeow worker --pool=solo -l info ``` ![BLOG_20181130_170738_36](/media/blog/images/2018/11/BLOG_20181130_170738_36.png "博客图集BLOG_20181130_170738_36.png") ### Linux下启动celery celery不能用root用户启动问题 `C_FORCE_ROOT environment` ```bash (StarMeow) root@StarMeow-Svr:~/django-web/StarMeow# celery -A StarMeow worker -l info /root/django-web/StarMeow/media/schedule/exportfiles/ Running a worker with superuser privileges when the worker accepts messages serialized with pickle is a very bad idea! If you really want to continue then you have to set the C_FORCE_ROOT environment variable (but please think about this before you do). User information: uid=0 euid=0 gid=0 egid=0 ``` 解决办法,在settings.py同级下的celery.py文件中增加 ```python from celery import Celery, platforms platforms.C_FORCE_ROOT = True #加上这一行 ``` ![BLOG_20181130_170747_18](/media/blog/images/2018/11/BLOG_20181130_170747_18.png "博客图集BLOG_20181130_170747_18.png") ## 使用flower检测队列运行情况 Windows下进行的 ```bat pip install flower (StarMeow) E:\Sync\OneDrive\PycharmProjects\StarMeow>celery flower -A StarMeow ``` 进入 http://localhost:5555 即可查看 ## celery+supervisor(后台进程) ### 配置python2虚拟环境 每个人虚拟环境不同,需要自行处理。 ``` pip install supervisor # python3不能使用 ``` 使用python2完成 ```bash root@StarMeow-Svr:~/django-web# pyenv install --list Available versions: # ... 2.7.15 # ... root@StarMeow-Svr:~/django-web# pyenv install 2.7.15 root@StarMeow-Svr:~/django-web# pyenv versions system 2.7.15 * 3.6.6 (set by /root/.pyenv/version) 3.6.6/envs/StarMeow StarMeow root@StarMeow-Svr:~/django-web# pyenv virtualenv 2.7.15 Supervisor Collecting virtualenv Downloading http://mirrors.tencentyun.com/pypi/packages/7c/17/9b7b6cddfd255388b58c61e25b091047f6814183e1d63741c8df8dcd65a2/virtualenv-16.1.0-py2.py3-none-any.whl (1.9MB) 100% |████████████████████████████████| 1.9MB 55.8MB/s Installing collected packages: virtualenv Successfully installed virtualenv-16.1.0 You are using pip version 9.0.3, however version 18.1 is available. You should consider upgrading via the 'pip install --upgrade pip' command. New python executable in /root/.pyenv/versions/2.7.15/envs/Supervisor/bin/python2.7 Also creating executable in /root/.pyenv/versions/2.7.15/envs/Supervisor/bin/python Please make sure you remove any previous custom paths from your /root/.pydistutils.cfg file. Installing setuptools, pip, wheel... done. Requirement already satisfied: setuptools in /root/.pyenv/versions/2.7.15/envs/Supervisor/lib/python2.7/site-packages Requirement already satisfied: pip in /root/.pyenv/versions/2.7.15/envs/Supervisor/lib/python2.7/site-packages root@StarMeow-Svr:~/django-web# pyenv virtualenvs 2.7.15/envs/Supervisor (created from /root/.pyenv/versions/2.7.15) 3.6.6/envs/StarMeow (created from /root/.pyenv/versions/3.6.6) StarMeow (created from /root/.pyenv/versions/3.6.6) Supervisor (created from /root/.pyenv/versions/2.7.15) root@StarMeow-Svr:~/django-web# pyenv versions system 2.7.15 2.7.15/envs/Supervisor * 3.6.6 (set by /root/.pyenv/version) 3.6.6/envs/StarMeow StarMeow Supervisor # 进入虚拟环境,激活 root@StarMeow-Svr:~/django-web# mkdir Supervisor root@StarMeow-Svr:~/django-web# cd Supervisor/ root@StarMeow-Svr:~/django-web/Supervisor# pyenv activate Supervisor (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# pip list Package Version ---------- ------- pip 18.1 setuptools 40.6.2 wheel 0.32.3 (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# pip install supervisor (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# pip list Package Version ---------- ------- meld3 1.0.2 pip 18.1 setuptools 40.6.2 supervisor 3.3.4 wheel 0.32.3 ``` 设置当前目录的python虚拟环境,`pyenv local Supervisor`中的Supervisor为虚拟环境名称,这样每次进入该目录就是python2虚拟环境 ```bash (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# pyenv local Supervisor ``` ### 生成supervisor配置文件 ``` # 生成supervisor配置文件,可以直接在当前目录生成,也可以指定位置 (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# echo_supervisord_conf > supervisord.conf (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# ls supervisord.conf ``` ### 生成celery.ini配置文件 我的项目的虚拟环境路径为**/root/.pyenv/versions/StarMeow/** 可以通过`root@StarMeow-Svr:~# /root/.pyenv/versions/StarMeow/bin/celery -A StarMeow worker -l info`测试(虽然启不动) 项目的路径为`/root/django-web/StarMeow` ```bash # 创建celery.ini文件 (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# vim celery.ini ``` ```ini # 配置内容 [program:celery] # celery命令的绝对路径 command=/root/.pyenv/versions/StarMeow/bin/celery -A StarMeow worker -l info # 项目路径 directory=/root/django-web/StarMeow # 日志文件路径 stdout_logfile=/var/log/myweb/celery.log # 自动重启 autorestart=true # 如果设置为true,进程则会把标准错误输出到supervisord后台的标准输出文件描述符 redirect_stderr=true ``` ### 添加celery配置到supervisord中 ```bash (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# vim supervisord.conf ``` 修改supervisord.conf文件,在最后增加 ```ini [include] files = celery.ini ``` ### 虚拟环境中启动 ```bash # 以守护进程的形式运行一组应用程序,指定配置文件 (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# supervisord -c supervisord.conf # 查看进程 (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# ps -ef | grep supervisord root 32133 1 0 15:54 ? 00:00:00 /root/.pyenv/versions/2.7.15/envs/Supervisor/bin/python2.7 /root/.pyenv/versions/Supervisor/bin/supervisord -c supervisord.conf root 32212 14833 0 15:54 pts/0 00:00:00 grep supervisord # 载入最新的配置文件,停止原有进程并按新的配置启动、管理所有进程 (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# supervisorctl reload # 更新新的配置到supervisord,启动新配置或有改动的进程,配置没有改动的进程不会受影响而重启 (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# supervisorctl update # 查看正在守护的进程 (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# supervisorctl status celery RUNNING pid 32171, uptime 0:15:08 # 子进程启停 (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# supervisorctl stop celery celery: stopped (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# supervisorctl start celery celery: started # 所有子进程启停 (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# supervisorctl stop all celery: stopped (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# supervisorctl start all celery: started ``` ### 不进虚拟环境启动 由于之前是进入虚拟环境中运行`supervisord`的,那么不进入虚拟环境怎么运行? ```bash root@StarMeow-Svr:~# /root/.pyenv/versions/2.7.15/envs/Supervisor/bin/supervisord -c /root/django-web/Supervisor/supervisord.conf root@StarMeow-Svr:~# ps -ef | grep supervisord root 4140 1 0 16:16 ? 00:00:00 /root/.pyenv/versions/2.7.15/envs/Supervisor/bin/python2.7 /root/.pyenv/versions/2.7.15/envs/Supervisor/bin/supervisord -c /root/django-web/Supervisor/supervisord.conf root 4371 2184 0 16:17 pts/1 00:00:00 grep supervisord ``` ### 创建自动重新加载脚本 ```bash root@StarMeow-Svr:~/django-web# vim SvReload.sh echo '正在更新Supervisor配置···' #! /bin/bash cd /root/django-web/Supervisor supervisorctl reload ``` 完成后保存授权 ```bash root@StarMeow-Svr:~/django-web# chmod +x SvReload.sh root@StarMeow-Svr:~/django-web# ./SvReload.sh 正在更新Supervisor配置··· Restarted supervisord ``` ## 业务运用 > 访问某个页面获取访问者IP,查询IP归属地,推送QQ消息 增加tasks.py函数 ```python from __future__ import absolute_import, unicode_literals from celery import shared_task from StarMeow.celery import app from utils.ip_attribution import get_ip_data_taobao, get_ip_data_ip138 # 获取IP地址归属地信息 from app_studio.qqbot.api import qqbot_api_data, qqbot_host_port # 用于qqbot接口 # @app.task @ shared_task def print_info(info): print('正在访问:{}'.format(info)) return None # 可以不返回 @app.task def send_qq_message(ip, article_title, absolute_uri): """ 发送QQ消息 :param ip: :param article_title: :param absolute_uri: :return: """ ip_info1 = get_ip_data_taobao(ip) ip_info2 = get_ip_data_ip138(ip) message = '又有人访问啦!\nIP:{}\n文章:《{}》({})\n地址参考1:{}\n地址参考2:{}'.format(ip, article_title, absolute_uri, ip_info1, ip_info2) qqbot_api_data(qqbot_host_port, '/send_group_msg', group_id=531809487, message=message) return '启动异步任务,发送访问信息到QQ' ``` 视图函数中调用 ```python # 访问写入日志 if get_request_ip(request) != '127.0.0.1': ip = get_request_ip(request) user_agent = get_request_agent(request) absolute_uri = get_request_uri(request) BlogRequestLog.objects.create(ip=ip, user_agent=user_agent, absolute_uri=absolute_uri) # 异步发送QQ消息 send_qq_message.delay(ip, article.title, absolute_uri) # 异步调用 # send_qq_message(ip, article.title, absolute_uri) # 相当于直接调用该函数 ``` ![BLOG_20181130_170805_89](/media/blog/images/2018/11/BLOG_20181130_170805_89.png "博客图集BLOG_20181130_170805_89.png") # Celery定时任务 只需要在settings文件中添加配置 `CELERYBEAT_SCHEDULE` 字段并在 `CELERY_IMPORTS` 中导入任务模块(可不要)就可以实现定时任务 ## 配置Django的settings增加定时 ```python from datetime import timedelta from celery.schedules import crontab CELERY_BEAT_SCHEDULE = { # 'add-every-xx-seconds': { # 'task': 'app_blog.blog.tasks.print_info', # 'schedule': timedelta(seconds=2), # 每 30 秒一次 # # 'schedule': timedelta(minutes=1), # 每 1 分钟一次 # # 'schedule': timedelta(hours=4), # 每 4 小时一次 # 'args': ('settings中的定时任务',) # 任务函数参数,如果只有一个参数,一定要加逗号 # }, 'send_qq_blog_request_count': { 'task': 'app_blog.blog.tasks.count_blog_everyday_request', 'schedule': crontab(hour=23, minute=30), # 每天晚上 23 点 30 分执行一次 } } ``` - `timedelta`是`datetime`中的一个对象,需要`from datetime import timedelta`引入,有如下几个参数 - `days`:天 - `seconds`:秒 - `microseconds`:微妙 - `milliseconds`:毫秒 - `minutes`:分 - `hours`:小时 - crontab的参数有: - `month_of_year`:月份 - `day_of_month`:日期 - `day_of_week`:周 - `hour`:小时 - `minute`:分钟 ## 增加定时任务的tasks函数 该定时任务的功能是统计每天博客访问量,在每天晚上 23 点 30 分发送QQ消息 ```python from app_blog.log.models import BlogRequestLog @app.task def count_blog_everyday_request(): today_request_count = BlogRequestLog.objects.filter(created_time__day=datetime.datetime.now().day).count() now_time_str = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") qqbot_api_data(qqbot_host_port, '/send_group_msg', group_id=531809487, message='博客访问统计!\n统计时间:{}\n今天我的博客共有{}次访问啦~~~'.format(now_time_str, today_request_count)) ``` ## 启动Celery的works和beat 启动 Celery Beat 进程,定时将任务发送到 Broker http://docs.celeryproject.org/en/latest/userguide/periodic-tasks.html ### Windows下启动 ```bat (StarMeow) D:\LR@ProjectsSync\OneDrive\PycharmProjects\StarMeow>celery -A StarMeow worker --pool=solo -l info (StarMeow) D:\LR@ProjectsSync\OneDrive\PycharmProjects\StarMeow>celery -A StarMeow beat -l info ``` ### Linux启动 ```shell (StarMeow) root@StarMeow-Svr:~/django-web/StarMeow#celery -A StarMeow worker -l info (StarMeow) root@StarMeow-Svr:~/django-web/StarMeow#celery -A StarMeow beat -l info ``` 因为works已经在supervisor中启动好了,只需要重新加载一下就行,然后启动beat,测试可以修改一下时间,看是否能正常执行定时任务 ![BLOG_20181201_221050_79](/media/blog/images/2018/12/BLOG_20181201_221050_79.png "博客图集BLOG_20181201_221050_79.png") ### 同时启动works和beat 如果你同时使用了异步任务和计划任务,有一种更简单的启动方式**`celery -A StarMeow worker -B -l info`**,可同时启动worker和beat(-B一定要大写的) ## celery+supervisor启动works和beat 只需要修改celery.ini配置文件里面的执行命令即可 ### 配置celery.ini ```bash root@StarMeow-Svr:~/django-web# cd Supervisor/ (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# ls celery.ini supervisord.conf (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# vim celery.ini ``` celery.ini ```ini # 配置内容 [program:celery] # celery命令的绝对路径 command=/root/.pyenv/versions/StarMeow/bin/celery -A StarMeow worker -B -l info # 项目路径 directory=/root/django-web/StarMeow # 日志文件路径 stdout_logfile=/var/log/myweb/celery.log # 自动重启 autorestart=true # 如果设置为true,进程则会把标准错误输出到supervisord后台的标准输出文件描述符 redirect_stderr=true ``` ### 重载 因为之前配置了自动重载脚本,只需要执行下即可 ```bash (Supervisor) root@StarMeow-Svr:~/django-web/Supervisor# cd .. root@StarMeow-Svr:~/django-web# ./SvReload.sh 正在更新Supervisor配置··· Restarted supervisord ``` ### 查看celery日志 ```bash root@StarMeow-Svr:~/django-web# cat /var/log/myweb/celery.log ``` ![BLOG_20181201_221042_24](/media/blog/images/2018/12/BLOG_20181201_221042_24.png "博客图集BLOG_20181201_221042_24.png") # Celery配置详解 在Django中配置如下 **settings.py** ```python # Celery+Redis实现异步任务,首先需要pip install celery # 配置参考 http://docs.jinkan.org/docs/celery/configuration.html#configuration # 配置Broker,因为在app.config_from_object('django.conf:settings', namespace='CELERY')设置了前缀,就需要加上,否则去掉CELERY_ if socket.gethostname() == 'starmeow-svr' or socket.gethostname() == 'StarMeow-Svr': # CELERY_BROKER_URL = 'redis://localhost:server_port/3' CELERY_BROKER_URL = 'redis://:redis_pass@127.0.0.1:server_port/3' # # 使用Redis作为消息代理 CELERY_RESULT_BACKEND = 'redis://:redis_pass@127.0.0.1:server_port/4' # 把任务结果存在了Redis,可以不要 else: CELERY_BROKER_URL = 'redis://:redis_pass@server_ip:server_port/3' # 服务器的redis CELERY_RESULT_BACKEND = 'redis://:redis_pass@server_ip:server_port/4' CELERY_BROKER_TRANSPORT = 'redis' CELERY_TASK_RESULT_EXPIRES = 60 * 60 * 24 # 任务过期时间,不建议直接写86400,应该让这样的magic数字表述更明显 CELERY_TIMEZONE = 'Asia/Shanghai' # 指定时区,默认是 UTC CELERY_TASK_SERIALIZER = 'pickle' # 任务序列化和反序列化使用pickle方案 CELERY_RESULT_SERIALIZER = 'json' # 读取任务结果一般性能要求不高,所以使用了可读性更好的JSON CELERY_ACCEPT_CONTENT = ['json', 'pickle'] # 指定接受的内容类型, 启用实际使用的序列化程序,不加似乎会出现警告 CELERYD_MAX_TASKS_PER_CHILD = 40 # 设置每个worker执行了多少任务就会死掉,长时间运行Celery有可能发生内存泄露 # CELERY_IMPORTS = ( # 指定导入的模块,不指定就导入所有 # 'app_blog.blog.tasks.print_info', # # ... # ) from datetime import timedelta from celery.schedules import crontab CELERY_BEAT_SCHEDULE = { # 'add-every-xx-seconds': { # 'task': 'app_blog.blog.tasks.print_info', # 'schedule': timedelta(seconds=2), # 每 30 秒一次 # # 'schedule': timedelta(minutes=1), # 每 1 分钟一次 # # 'schedule': timedelta(hours=4), # 每 4 小时一次 # 'args': ('settings中的定时任务',) # 任务函数参数,如果只有一个参数,一定要加逗号 # }, 'send_qq_blog_request_count': { 'task': 'app_blog.blog.tasks.count_blog_everyday_request', 'schedule': crontab(hour=23, minute=30), # 每天晚上 23 点 30 分执行一次 } } ``` **celery.py** ```python # StarMeow/StarMeow/celery.py from __future__ import absolute_import, unicode_literals import os import django from celery import Celery, platforms from django.conf import settings # 为“celery”程序设置默认的Django settings模块。 os.environ.setdefault('DJANGO_SETTINGS_MODULE', 'StarMeow.settings') django.setup() # 使用settings.py中的相关配置,不加这个,就会提示app参数不够 # 如果不加django.setup(),下面就需要使用app = Celery('StarMeow', broker='...broker配置地址...') app = Celery('StarMeow') # 在这里使用字符串意味着worker不必序列化子进程的配置对象。 # namespace ='CELERY'表示所有与celery相关的配置键应该有一个`CELERY_`前缀, # 例如settings.py中的CELERY_BROKER_URL,这个就需要加CELERY_前缀,不定义namespace,则不加前缀。 app.config_from_object('django.conf:settings', namespace='CELERY') # 参考http://docs.jinkan.org/docs/celery/getting-started/first-steps-with-celery.html#celerytut-configuration 可以在本文件写配置 # app.conf.update( # 可以在这个位置加定时任务,和在settings中一样 # CELERY_BEAT_SCHEDULE={ # 'add-every-xx-seconds': { # 'task': 'app_blog.blog.tasks.print_info', # 'schedule': timedelta(seconds=2), # 每 30 秒一次 # 'args': ('celery中的定时任务',) # 任务函数参数,如果只有一个参数,一定要加逗号 # }, # } # ) # 从所有注册的Django app configs加载任务模块。 # app.autodiscover_tasks() app.autodiscover_tasks(lambda: settings.INSTALLED_APPS) # 也可以使用这行,只添加INSTALLED_APPS中的app platforms.C_FORCE_ROOT = True # Linux在root用户下不能启动,需要添加这一行 @app.task(bind=True) def debug_task(self): print('Request: {0!r}'.format(self.request)) ```
很赞哦! (2)
相关文章
文章交流
- emoji