本文首发于公众号:Hunter后端

原文链接:celery笔记一之celery介绍、启动和运行结果跟踪

本篇笔记内容如下:

  1. celery 介绍
  2. celery 准备
  3. celery 启动和异步任务的运行
  4. 运行结果跟踪

1、celery 介绍

celery 大致有两种应用场景,一种是异步任务,一种是定时任务。

比如说在一个接口请求中,某个函数执行所需的时间过长,而前端页面并不是立刻需要在接口中获取处理结果,可以将这个函数作为异步任务,先返回给前端处理中的信息,在后台单独运行这个函数,这就是异步任务。

另一个比如说某个函数需要每天晚上运行一遍,不可能人天天守着后台手动执行一遍这个函数,那么就可以用 celery 来实现这个定时的周期任务。

接下来介绍一下 celery 的组成:

task

这个任务就是我们前面举的例子的异步任务或者是定时任务,即为 task,我们可以定义这些任务,然后发送到 broker

broker

broker 可以理解成消息中间件,用于获取异步或者定时任务,形成一个或多个消息队列,然后发送给 worker 处理这些消息

broker 的形式可以是 Redis,RabbitMQ 或者其他,这里我们使用 Redis 作为消息中间件

worker

worker 是处理消息的程序,获取 broker 中的消息,然后在 worker 中执行,然后根据配置决定将处理结果发送到 backend

result_backend

在 worker 处理完消息之后会有 return 或者没有返回结果,都会根据配置将结果发送出来,可以配置成发送到 redis 中,也可以将之存储到 database 中

beat

主要用于调用定时任务,根据设定好的定时任务,比如每天晚上十点执行某个函数,beat 则会在相应的时间将这个 task 发送给 broker,然后 worker 获取任务进行处理

定时任务除了说的每天晚上十点这种周期任务,也可以是间隔任务,比如说每隔多少秒,多少分钟执行一次

注意:异步任务的发送是不经过 beat 处理,直接发送给 broker 的

在上面的结构中,broker 需要将相应的服务比如 redis 运行起来,而 worker 和 beat 需要在手动用程序运行,而且每次更改了定时策略之后需要重新启动 beat 和 worker 才能生效。

2、celery 准备

接下来我们实现一个最简单的异步任务,在执行异步任务前,我们做如下的准备工作

1.安装依赖

我们需要安装一下 celery 和 redis 的依赖:

pip3 install celery==5.1.2 -i https://mirrors.aliyun.com/pypi/simple/
pip3 install redis==3.5.3 -i https://mirrors.aliyun.com/pypi/simple/

2.消息中间件

这里我们用到的消息中间件是 redis,可以去官网下载一个 redis 启动,也可以使用 docker 来执行安装。

我在之前的 docker 系列笔记中有介绍过如何拉取镜像和运行容器,我们这里直接使用 docker 来运行:

docker run -itd -p 6379:6379 redis:latest

3.异步任务准备

我们准备一个最简单的 add() 函数,放在 tasks.py 文件中:

# tasks.py
from celery import Celery app = Celery('tasks', broker='redis://localhost/0', backend='redis://localhost/1') @app.task
def add(x, y):
return x + y

在这段代码里,我们引入 Celery 模块,并将其实例化为 app,且配置了 broker 参数,表示消息队列都会被放在 redis 的第一个数据库下

指定的 backend 参数则表示函数运行的结果被放在 redis 的第二个数据库下

然后用 @app.task 修饰 add 函数,表示它是 app 下的 task 任务

以上,我们的准备工作就完成了,接下来尝试运行这个异步任务

3、celery 启动和异步任务的运行

说是 celery 的启动,其实是 worker 的启动,中间件是 redis,已经在前面的步骤中启动了。

我们在 tasks.py 所在的文件夹下执行下面的命令:

celery -A tasks worker -l INFO

在这里,tasks 是我们任务所在的文件名,worker 表示启动的是 worker 程序

-l INFO 则会在控制台打印出 worker 接收到的消息详情,如果不执行,则信息流不会被打印出来

执行了上面的程序后,可以看到控制台会输出下面这种信息:


-------------- celery@localhost v5.1.2 (sun-harmonics)
--- ***** -----
-- ******* ---- Darwin-21.4.0-x86_64-i386-64bit 2022-07-17 23:56:09
- *** --- * ---
- ** ---------- [config]
- ** ---------- .> app: tasks:0x7fc8ddf3df98
- ** ---------- .> transport: redis://localhost:6379/0
- ** ---------- .> results: disabled://
- *** --- * --- .> concurrency: 12 (prefork)
-- ******* ---- .> task events: OFF (enable -E to monitor tasks in this worker)
--- ***** -----
-------------- [queues]
.> celery exchange=celery(direct) key=celery [tasks]
. tasks.add [2022-07-17 23:56:09,685: INFO/MainProcess] Connected to redis://localhost:6379/0
[2022-07-17 23:56:09,699: INFO/MainProcess] mingle: searching for neighbors
[2022-07-17 23:56:10,737: INFO/MainProcess] mingle: all alone
[2022-07-17 23:56:10,780: INFO/MainProcess] celery@localhost ready.

则表示 worker 启动成功

执行异步任务

在另一个 shell 窗口,进入 python 的交互界面,输入以下命令:

from tasks import add
res = add.delay(1,2)

add 是我们需要执行的异步任务的函数名

delay 是异步任务执行的特有方法,这个其实是 apply_async() 函数的简便写法,不带任何参数,apply_async() 除了可以实现异步任务的功能,还可以指定多少时间后执行,比如说二十秒后执行,这个在后面的笔记中我们再介绍。

而异步任务的返回我们这里用 res 来定义,它是一个包含了这个任务所有执行信息对象,有任务状态(是否执行成功),有返回结果(add() 函数的return),还有这个 task 特有的标识 id等信息

至此,我们的一个异步任务的执行就完成了,我们可以在下一步查看它的运行结果等信息。

4、运行结果跟踪

接下来,我们在 tasks.py 中建立下面几个函数,来测试我们对结果的跟踪:

# tasks.py

import time
from celery import Celery app = Celery('tasks', broker='redis://localhost/0', backend='redis://localhost/1') @app.task
def add(x, y):
return x + y @app.task
def div(x, y):
return x / y @app.task
def test_not_finished():
time.sleep(30)
return True

然后重新运行 worker:

celery -A tasks worker -l INFO

然后引入和执行函数:

from tasks import add, div, test_not_finished

获取延时任务的结果

res = add.delay(1, 2)
print(res.result) # 也可以使用 get()
print(res.get())

get() 函数也可以加个超时的设置:

res.get(timeout=2)

但是这样需要注意,因为如果超时了还未获取到结果,程序就会报错

判断函数运行是否完成

print(res.ready())

打印出的结果为 True 则表示函数运行完成

我们可以测试函数为完成的状态:

res2 = test_not_finished.delay()

在这个函数里,我们设置了 30s 的休眠,所以在 30s 內我们打印结果可以看到 res2.ready() 是为 False 的:

print(res2.ready())

获取task id

每个被执行的 task 都有各自对应的 id 作为它们的唯一键:

print(res.id)

查看任务执行的状态

# 任务执行是否失败,返回 布尔型数据
is_failed = res.failed() # 任务执行是否成功,返回布尔型数据
is_successful = res.successful() # 执行的任务所处的状态
state = res.state
# state 的值会在 PENDING,STARTED,SUCCESS,RETRY,FAILURE 这几种状态中,分别是 待处理中,任务已经开始,成功,重试中,失败

报错处理

如果执行的延时任务在程序中报错,比如我们定义的 div() 函数,我们传入的除数为 0 的话,在程序中是会报错的,我们使用 get() 来获取结果的话程序是会报错的:

res3 = div.delay(3, 0)
res3.get() # 返回会报错

但是我们可以使用 propagate=False 参数来忽略程序的报错:

res3.get(propagate=False)

这样我们获取的就不是程序报错,而是程序报错的信息作为结果返回

使用 res3.state 发现返回的结果是 FAILURE

当延时任务在程序中报错,它的返回值就不会是正确的,我们可以通过 res3.traceback 是否有值来判断函数运行过程中是有报错:

if res3.traceback:
print("延时任务报错")
else:
print("程序正常运行,可以获取返回值")

result资源释放

因为 backend 会使用资源来保存和传输结果,为了确保资源被释放,所以在执行完异步任务后,你必须对每一个结果调用 get() 或者 forget() 函数

result.get() 函数获取结果

result.forget() 在 backend 删掉该数据

在官方文档上,意思是 get() 和 forget() 方法都可以释放资源,但是经过我测试,貌似只有 forget() 函数会释放资源

查看是否资源被释放也很简单,登录到对应的 backend,我这里是 redis,使用 redis-cli 或者通过 docker 进入 redis:

select 1

keys*

查看相应的 task id 是否还在列表就可以知道该资源是否被释放

如果不想手动释放资源,可以在配置里设置一个过期时间,那么结果就会在指定时间段后被释放:

app.conf.update(result_expires=60)

这个我们可以在后面的配置里再详细介绍。

以上就是本篇笔记全部内容,下一篇笔记我们将介绍如何建立一个 celery 项目、配置的几种方法及一些基本的配置。

如果想获取更多后端相关文章,可扫码关注阅读:

celery笔记一之celery介绍、启动和运行结果跟踪的更多相关文章

  1. Celery笔记

    异步任务神器 Celery 简明笔记 2016/12/19 · 工具与框架 · Celery, 异步 原文出处: FunHacks    在程序的运行过程中,我们经常会碰到一些耗时耗资源的操作,为了避 ...

  2. celery 分布式异步任务框架(celery简单使用、celery多任务结构、celery定时任务、celery计划任务、celery在Django项目中使用Python脚本调用Django环境)

    一.celery简介: Celery 是一个强大的 分布式任务队列 的 异步处理框架,它可以让任务的执行完全脱离主程序,甚至可以被分配到其他主机上运行.我们通常使用它来实现异步任务(async tas ...

  3. Java基础笔记 – Annotation注解的介绍和使用 自定义注解

    Java基础笔记 – Annotation注解的介绍和使用 自定义注解 本文由arthinking发表于5年前 | Java基础 | 评论数 7 |  被围观 25,969 views+ 1.Anno ...

  4. Andrew Ng机器学习课程笔记--week1(机器学习介绍及线性回归)

    title: Andrew Ng机器学习课程笔记--week1(机器学习介绍及线性回归) tags: 机器学习, 学习笔记 grammar_cjkRuby: true --- 之前看过一遍,但是总是模 ...

  5. Python3安装Celery模块后执行Celery命令报错

    1 Python3安装Celery模块后执行Celery命令报错 pip3 install celery # 安装正常,但是执行celery 命令的时候提示没有_ssl模块什么的 手动在Python解 ...

  6. [学习笔记] 下载、安装、启动 Eclipse(OEPE)

    OEPE 的全称是: Oracle Enterprise Pack for Eclipse 截止目前的最新版本是:(12.2.1.9) 下载地址:(需要在甲骨文官网注册一个账户才能下载) https: ...

  7. AppleWatch开发教程之Watch应用对象新增内容介绍以及编写运行代码

    AppleWatch开发教程之Watch应用对象新增内容介绍以及编写运行代码 添加Watch应用对象时新增内容介绍 Watch应用对象添加到创建的项目中后,会包含两个部分:Watch App 和 Wa ...

  8. Docker学习笔记之一,搭建一个JAVA Tomcat运行环境

    Docker学习笔记之一,搭建一个JAVA Tomcat运行环境 前言 Docker旨在提供一种应用程序的自动化部署解决方案,在 Linux 系统上迅速创建一个容器(轻量级虚拟机)并部署和运行应用程序 ...

  9. 如何在ASP.NET Core程序启动时运行异步任务(2)

    原文:Running async tasks on app startup in ASP.NET Core (Part 2) 作者:Andrew Lock 译者:Lamond Lu 在我的上一篇博客中 ...

  10. 如何在ASP.NET Core程序启动时运行异步任务(1)

    原文:Running async tasks on app startup in ASP.NET Core (Part 1) 作者:Andrew Lock 译者:Lamond Lu 背景 当我们做项目 ...

随机推荐

  1. 【读书笔记】格子路径计数LatticePathEnumeration 学一半的笔记

    流水账流水账这篇什么都不是 目录 方法 10.2 Lattice paths without restrictions 无限制格子路径 2维的例子,从(a,b)到(c,d),允许(0,1)和(1,0) ...

  2. 更优雅的OrientDB Java API

    OrientDB API v1.0.0(OrientDB 3.x) Gitee OrientDB介绍 OrientDB是一个开源的NoSQL数据库管理系统,同时也是一款高性能的图数据库,支持ACID事 ...

  3. CPU内部的奥秘:代码是如何被执行的?

    我们是袋鼠云数栈 UED 团队,致力于打造优秀的一站式数据中台产品.我们始终保持工匠精神,探索前端道路,为社区积累并传播经验价值. 本文作者:景明 我们以一段 C 代码为例,来看一下代码被编译成二进制 ...

  4. Junit环境配置和在IDEA中使用Junit学习记录

    Junit环境配置 步骤1:检查电脑中Java环境是否配置成功 因为JUnit 是 Java 的一个框架,所以最根本的需要是在你的机器里装有 JDK. 1.1 进入cmd控制台界面,输入java/ja ...

  5. Oracle_数据泵

    Oracle数据泵导入.导出数据 expdp导出 运行CMD 登录数据库,输入sqlplus 使用管理员角色登录需要在用户名后加" as sysdba" 例如:sys as sys ...

  6. 第三章3.1HTML技术与CSS技术

    web中的html以及css: html(超文本标记语言:Hyper Text Markup Language):用于描述网页的一种语言: 通常其根标签使用html标签:使用尖括号表示:<htm ...

  7. python入门教程之八列表,字典,字符串,集合常用操作

    一列表常用方法 Python包含以下函数: 序号 函数 1 cmp(list1, list2)比较两个列表的元素 2 len(list)列表元素个数 3 max(list)返回列表元素最大值 4 mi ...

  8. QtDesigner安装

    QtDesigner简单介绍 Qtdesigner是Python设计里面一个非常实用的工具,使得人们编写qt界面可以不仅仅是使用纯代码,而可以在可视化的基础上设置,非常方便. QtDesigner安装 ...

  9. Python pip速度慢,更换源

    版权声明:本文为CSDN博主「cocoprince」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明.原文链接:https://blog.csdn.net/Coco ...

  10. 使用select需要注意的细节

    使用select需要注意的细节 在学校的时候就使用过select,但是在项目中使用的时候却犯了个错误. select如何使用就不进行总结了,网上教程太多,以下是项目中我写的一小段代码,便于总结. in ...