捣鼓了两天自己的直播通项目,终于大概有了雏形,在主页的视图函数中集成了爬虫,爬取用户关注主播的在线hangtag。但在运行时发现打开主页时延迟明显,有时候竟然长达数秒,突然想起了之前了解到的celery,试试能不能解决这一问题。
celery是什么
关于celery的知识全部在网上了解,星星点点,但还是有所收获。celery是一个典型的异步任务系统,在应用上下文之外执行任务,将消耗资源的东西通通交给celery来做,可以让主机迅速向应客户端的请求。
celery有三个核心组件:
- 客户端:在flask系统中和flask一起运行
- workers:就是传说中的second terminal,用来执行异步任务,可以有多个
- 消息代理:用来进行celery的通信,一般用redis。
为什么用redis?因为其实时性强,一般用作数据频繁插入,更新或者删除的任务中,以减少对数据库的操作
让celery跑起来
这部分还是比较简单的,有几个主要步骤。
- 安装之后要在配置文件中写入用作消息代理的redis的服务器,两行搞定。
CELERY_BROKER_URL = 'redis://localhost:6379/0' CELERY_RESULT_BACKEND = 'redis://localhost:6379/0'
- 之后创建celery实例,这里是直接抄来的,至于原因还没搞懂。
celery = Celery(__name__, broker=Config.CELERY_BROKER_URL) celery.conf.update(app.config)
- 创建celery任务,使用装饰器,先跑起来再说。
@celery.task(name='circle_task') def circletask(): logging.info('lalala')
之后满怀信心,直接打开三个终端开始有样学样,第一个打开redis-server,第二个运行app,第三个打开celery,抄了个命令:
$ celery -A manage.celery worker --loglevel=info
然而打开后发现没有动静,才想起并没有提供任务执行的delay。随即又想到我的目的是进行计划任务,让任务可以固定时间重复进行,直接开始搜celery进行实现的方法,还好google够强大,又找到了下面的配置方法:
CELERYBEAT_SCHEDULE = {
'every-minute': {
'task': 'circle_task',
#'schedule': crontab(minute='*/1'),
# 'args': (1,2),
'schedule': timedelta(seconds=60)
},
}
运行命令也变成了:
$ celery -A manage.celery worker --loglevel=info --beat
$ celery -A proj worker -B -l info
至于里面的参数,只知道timedelta和crontab都可以设置间隔时间,其他的没有深入了解。将代码改好后运行celery,问题来了。
- 首先是celery说任务方法没有注册:
Received unregistered task of type 'circle_task'. The message has been ignored and discarded.
在stack overflow溜达了一圈,终于找到解决方法,在配置文件中声明这个方法即可,于是:
CELERY_IMPORTS = ['app.task']
解决成功。这里千万注意加app,天知道我经历了什么。
- 之后运行celery,终于不报错了天呐,屏幕上也出现了lalala的logging,这还说什么,改代码!在task中添加了之前在index视图函数中的爬虫部分,运行celery,好,可以运行。等等,这一大片红字是什么!
'RuntimeError: application not registered on db instance and no application bound to current context
原来是没有程序上下文不能进行sqlalchemy的操作,于是,在程序段前添加
with app.app_context():
成功!
最后终于成功看到了模拟上线提醒的logging字样,激动万分,编程的大起大落真是…哈!