python huey中文文档(二)

紧接着上回继续翻译吧。有关huey这个python写的的轻量级消息队列

个人才疏学浅,可能很多英文都要借助翻译软件,但尽量做到能够易于理解。


教程指导

这个文档的目的是为了帮助人尽可能快速使用huey

简单入门

使用huey需要注意有如下三个主要的组成(或者过程):

  • 生产者,例如web应用等。
  • 消费者,运行放置在消息队列中的任务(jobs)。
  • 队列,存放任务。例如Redis等。

底下的截图展示了上述三个不同的过程。左边是生产者:一个简单的程序询问用户要输入多少的“豆子”。右上角消费者一直运行,它正在做“计算”,举例如图中所示打印了有多少“豆子”被计数。右下角是是一个队列,图中使用的是Redis。我们可以看到任务被添加(LPUSH)入队列和从数据库中读取(BRPOP)任务。

截图

自我尝试

假定你安装了huey,让我们来看一下代码例子。
第一步先配置队列。消费者需要指定一个Huey实例,这代表了使用的后端类型。

# config.py
from huey import RedisHuey

huey = RedisHuey()

huey对象封装了队列。队列负责存储和取回消息,你的应用程序代码使用huey实例来联系函数调用。我们来看一下怎么使用huey来连接一个计算豆子的函数:

# tasks.py
from config import huey # import the huey we instantiated in config.py


@huey.task()
def count_beans(num):
    print('-- counted %s beans --' % num)

上述代码展现了如何用API定义最终被消费者执行的“任务”——用task()装饰器简单装饰你想要让消费者运行的函数任务。而当它被调用时候,主进程将立即返回而不是进入函数内部。在消费者进程中会看到这个新消息并运行这个函数。
我们的主程序很简单。它导入了配置和任务——这确保了在我们根据指定的配置运行消费者时,所有任务都会被加载入内存。

# main.py
from config import huey  # import our "huey" object
from tasks import count_beans  # import our task


if __name__ == '__main__':
    beans = raw_input('How many beans? ')
    count_beans(int(beans))
    print('Enqueued job to count %s beans' % beans)

启动脚本需要依次进行以下步骤:

  1. 确保本地运行Redis
  2. 确保安装了huey
  3. 启动消费者: huey_consumer.py main.huey(注意是"main.huey"而不是"config.huey",这里提示一下huey_consumer.py需要自己从huey脚本的bin下拷贝到当前的路径,这样才能用该命令来启动。)
  4. 运行主程序: python main.py

获取结果

上面的例子实现了一个“发送并且忘记”的方法,但是如果你的应用程序需要对任务的结果做些什么呢?要从你的任务中获取结果,只需返回任务函数中的值即可。

如果你得到了存储结果但不使用它们,那么可能会浪费大量空间,特别是如果你的任务量很高。要禁用存储功能,可以在初始化Huey实例时返回None或指定result_store = False

为了更好地说明获取结果的代码,我们还将修改tasks.py模块以返回一个字符串,而不是打印结果到标准输出窗口:

from config import huey


@huey.task()
def count_beans(num):
    print('-- counted %s beans --' % num)
    return 'Counted %s beans' % num

我们准备向消费者输入大量任务。不是简单地执行主程序,我们这回将启动一个解释器并运行以下操作:

>>> from main import count_beans
>>> res = count_beans(100)
>>> print(res)                      # What is "res" ?
<huey.api.TaskResultWrapper object at 0xb7471a4c>

>>> res()                          # Get the result of this task
'Counted 100 beans'

按照与上一个例子相同的布局,下面是三个主要工作流程的截图:

  1. 左边,解释器生成任务并询问结果
  2. 右上角, 消费者执行任务并存储结果
  3. 右下角是Redis数据库,我们能够看到它储存结果然后在我们取回数据后删除它们
结果

延迟执行任务

将某个特定任务排入任意时间来执行通常很用的,例如,标记在某个时间发布的博客条目。
这在huey中很容易完成。返回上一节描述的在解释器中执行的代码,让我们安排一个一分钟后执行的数豆子的任务,然后看看huey怎么处理它。执行以下代码:

>>> import datetime
>>> res = count_beans.schedule(args=(100,), delay=60)
>>> print(res)
<huey.api.TaskResultWrapper object at 0xb72915ec>

>>> res()  # This returns None, no data is ready.

>>> res()  # A couple seconds later.

>>> res(blocking=True)  # OK, let's just block until its ready
'Counted 100 beans'

你也可以使用datetime类型来指定“预计到达时间”:

>>> in_a_minute = datetime.datetime.now() + datetime.timedelta(seconds=60)
>>> res = count_beans.schedule(args=(100,), eta=in_a_minute)

默认情况下,Huey实例以UTC时间运行。这对计划任务的影响是,当使用本地的时间时,它们必须与datetime.utcnow()相关联。

在上述代码中我们不采用utcnow()的原因是schedule()包含默认值为True的第三个参数叫做convert_utc。所以在上面的代码中,datetime在被发送到队列之前从本地时间转换为了UTC

当你想要以本地时间模式运行(-o),你需要总是指定schedule()的第三个参数convert_utc=False,包括在指定delay参数时。

redis的输出,我们看到以下(简化内容):

+1325563365.910640 "LPUSH" count_beans(100)
+1325563365.911912 "BRPOP" wait for next job
+1325563365.912435 "HSET" store 'Counted 100 beans'
+1325563366.393236 "HGET" retrieve result from task
+1325563366.393464 "HDEL" delete result after reading

截图也展示了相同的内容:

安排

重试失败任务

Huey支持有限次重试失败任务。如果在执行任务期间引发了异常,但是你已经指定了retries参数,则任务将重新入队并再次尝试,直到指定的重试次数。
如下显示的一个任务,将重试3次,每次都会抛出异常:

# tasks.py
from config import huey


@huey.task()
def count_beans(num):
    print('-- counted %s beans --' % num)
    return 'Counted %s beans' % num

@huey.task(retries=3)
def try_thrice():
    print('trying....')
    raise Exception('nope')

控制台输出显示我们的任务在解释器会话中被调用,然后当消费者接收然后执行它时,我们看到它失败但进行了重试:

重试

在重试之间等待一定的时间间隔通常是个好的主意。你可以指定重试之间的delay参数(以秒为单位),这会是任务重试之前等待的最短时间。这里我们修改代码使它包含delay参数,并打印当前时间来显示它的工作。

# tasks.py
from datetime import datetime

from config import huey

@huey.task(retries=3, retry_delay=10)
def try_thrice():
    print('trying....%s' % datetime.now())
    raise Exception('nope')

下面的控制台输出显示正在重试的任务,同时在重试过程中,我还在添加了“数豆子”的任务——处于正常执行状态。

添加延迟

定期任务

huey支持的另一个使用模式是定期执行任务。依照crontab行为,同时遵循类似的语法。定期执行的任务,不应返回有意义的结果,也不应接受任何参数。
让我们添加一个每分钟打印一次字符窜的新任务——我们将使用它来测试消费者是否正在按计划执行任务。

# tasks.py
from datetime import datetime
from huey import crontab

from config import huey

@huey.periodic_task(crontab(minute='*'))
def print_time():
    print(datetime.now())

现在,当我们运行消费者时,它将每分钟开始打印时间:

定时任务

取消或暂停任务

huey可以停止任务执行。这适用于正常任务,延迟任务和定期任务。
为了“revoke(撤销)”任务,你需要在实例化Huey对象时指定一个result_store参数。
如果消费者没有开始执行任务,你可以取消正常的任务:

# count some beans
res = count_beans(10000000)

# provided the command has not started executing yet, you can
# cancel it by calling revoke() on the TaskResultWrapper object
res.revoke()

这同样适用于延迟任务:

res = count_beans.schedule(args=(100000,), eta=in_the_future)
res.revoke()

# and you can actually change your mind and restore it, provided
# it has not already been "skipped" by the consumer
res.restore()

要撤消给定任务的所有实例,请对任务本身使用revoke()restore()方法:

count_beans.revoke()
assert count_beans.is_revoked() is True

res = count_beans(100)
assert res.is_revoked() is True

count_beans.restore()
assert count_beans.is_revoked() is False

取消或暂停定期任务

当我们开始处理定期任务时,撤销选项会更有意思。
我们将使用打印时间代码作为示例:

@huey.periodic_task(crontab(minute='*'))
def print_time():
    print(datetime.now())

我们可以防止周期性的任务在下一个循环中执行:

# only prevent it from running once
print_time.revoke(revoke_once=True)

由于上述任务每分钟执行一次,我们将看到输出将跳过下一次的一分钟,然后才恢复正常。
我们也可以防止任务执行直到指定时间:

# prevent printing time for 10 minutes
now = datetime.datetime.utcnow()
in_10 = now + datetime.timedelta(seconds=600)

print_time.revoke(revoke_until=in_10)

当指定revoke_until设置,如果消费者以UTC默认时间模式运行,本地时间需要关联到datetime.utcnow()。如果消费者以本地时间(-o参数指定),则可以使用datetime.now()

最后,我们可以防止任务无限期地运行:

# will not print time until we call revoke() again with
# different parameters or restore the task
print_time.revoke()
assert print_time.is_revoked() is True

我们随时可以恢复任务,它将会正常执行:

print_time.restore()

查看更多

这总结了huey的基本使用模式。以下是有关API其他方面的详细信息的链接:

结束

有一周混过去了,继续啃爬虫去了。。。。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,542评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,596评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 158,021评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,682评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,792评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,985评论 1 291
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,107评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,845评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,299评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,612评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,747评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,441评论 4 333
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,072评论 3 317
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,828评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,069评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,545评论 2 362
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,658评论 2 350

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,637评论 18 139
  • 本文章是 Vert.x 蓝图系列 的第二篇教程。全系列: Vert.x Blueprint 系列教程(一) | 待...
    sczyh30阅读 2,021评论 0 10
  • 来源 RabbitMQ是用Erlang实现的一个高并发高可靠AMQP消息队列服务器。支持消息的持久化、事务、拥塞控...
    jiangmo阅读 10,353评论 2 34
  • 41.多用派发队列,少用同步锁 在Objective-C中,如果有多个线程要执行同一份代码,那么有时可能会出问题。...
    Code_Ninja阅读 1,135评论 1 13
  • GCD调度队列是执行任务的强大工具。调度队列允许您相对于调度者异步或者同步的执行任意代码块。您能够使用调度队列来执...
    坤坤同学阅读 6,668评论 1 3