跳到主要内容

事件传播与优先级

当我们有很多handlercommand时,很可能有这样的场景

  • 我希望实现一个拦截性质的handler,对事件进行预处理,只有满足要求时,才放行给后续的其他handler处理
  • 我希望实现选择性的执行某些handler,当执行了其中任何一个,就放弃执行其他的handler

接下来,我们将介绍如何实现第一条,第二条如何实现,见权限控制

PepperBot的事件传播机制

当接受到一个事件时,PepperBot会将所有可用的handlercommand,按照priority进行排序,priority越大,越靠前

默认情况下,如果没有任何handlercommand阻断事件的传播(stop propagation),那么就依次执行

如果有handlercommand阻断了事件的传播,那么就不会执行后续的handlercommand

但是,有一个前提,就是handlercommand必须设置concurrencyFalse

handler的并发执行

对于大多数的使用场景来说,我们希望handler是并发执行的,这样可以提高性能

如果不并发(也就是顺序执行),会是什么样子呢?

假设我们有一个比较耗时的、并且是阻塞的handler,那么直到这个handler执行完毕,PepperBot才会继续执行后续的handler

如果handler之间并没有逻辑上的联系(也就是说,无所谓执行的先后顺序),那么这样的执行方式,显然会显著的降低响应速度(因为要等待之前的handler执行完毕)

PepperBot如何处理,同时存在并发执行顺序执行的情况

假设我们有这样几个handlercommand

priorityconcurrencytypename
500Trueclass_handlerhandler1
400Trueclass_commandcommand1
300Falseclass_handlerhandler2
200Falseclass_commandcommand2
100Trueclass_handlerhandler3
0Trueclass_commandcommand3

可以看到,handler2command2是顺序执行的,而其他的handlercommand是并发执行的

同时,因为handler1command1priorityhandler2command2大,所以handler1command1会先于handler2command2执行

因为handler2command2是非并发的,所以handler3command3会在handler2command2执行完毕后,才会执行

或者换句话说,如果在按照priority排序后的handler中,如果存在非并发的handler,则会在执行该handler之前,会等待该handler之前所有的并发handler执行完毕

顺序执行以实现事件传播的控制

只有当一个handler或者command执行完成,我们才能知道,该handler是否阻断了事件的传播

从上图可以看到,handler1command1是并发执行的,所以假设handler1阻断了事件的传播,因为并发(同时)执行的原因,此时command1已经执行了,所以此时stop propagation并未起效,虽然handler1优先级command2的高

但是,对于handler2来说,它是顺序执行的,所以在handler2执行之前,会等待handler1执行完毕,此时,如果handler1阻断了事件的传播,那么handler2就不会执行了

所以总结一下,如果我们希望实现事件传播的控制,那么我们可以将handlercommand设置为顺序执行,这样就可以在handlercommand执行完毕后,知道是否阻断了事件的传播

通过对传播进行分组,避免干扰

回到我们一开始假设的场景

我希望实现一个拦截性质的handler,对事件进行预处理,只有满足要求时,才放行给后续的其他handler处理

如果我的这个拦截handler,只想作用于后续的handler2,而完全不关心其他的handler

假设此时拦截handler阻断了传播,虽然确实实现了拦截handler2的执行,但是同时,也影响了其他的handler

那么,我们可以通过对传播进行分组,来避免这种干扰

现在,当拦截handler阻断了传播时,只会影响同一个传播组中的handler2,而不会影响到其他传播组

多个传播组之间,既然没有了逻辑上的联系,自然也是并发执行的

具体如何设置

  • priority默认为0
  • concurrency默认为True
  • propagation_group默认为default

设置class_handler

from pepperbot.store.event import PropagationConfig

class MyHandler:
config = PropagationConfig(
priority=100,
concurrency=False,
propagation_group="test",
)

async def group_message(self, ...):
...

设置class_command

@as_command(
...
priority=100,
concurrency=False,
propagation_group="test",
)
class MyCommand:
...