8. 事件

正常来讲,对于具体的事件不应该是 Transaction DSL 层面应该关注的事情,它需要做的就是将收到事件派发给由用户编写的基本操作。 具体基本操作打算如何处 理这些事件,那是那个层面应该关心的问题。

但在某些场景下,将对具体事件的关注放在 Transaction DSL 内,将会大大方便用户的实现。

8.1. __wait

首先的一种场景是,当一个事务执行到某个点的时候,会期待某个事件的发生,但是,事件的内容并不重要(或干脆没有内容),此时, 一个事件就像一个 signal 一样。如果由基本操作来关心这个事件,则用户不得不按照固定的模式编写一个类,以期待这个事件, 并在收到这个事件后,返回 SUCCESS , 比如:

DEF_SIMPLE_ASYNC_ACTION(Action1) {
  auto exec(const TransactionInfo&) -> Status {
    return WAIT_ON(EV_SOMETHING, handleSomethingEvent);
  }
private:
  auto handleSomethingEvent(TransactionInfo const&, Event& const) -> Status {
     return SUCCESS;
  }
};

这无疑是一件相当无聊的工作。为了方便于实现这样的场景,用户可以在 Transaction DSL 中使用 __wait 来完成相同的事情。如下:

__transaction
( ...
, __wait(EV_SOMETHING)
, ... );

8.2. __peek

在一些场景下,一个消息可能两个操作都关注,但是,放在前面的操作仅仅关心消息的到达,而放在后面的操作则更关心消息的内容。

这种情况下,前者可以使用 __peek 来探测一个消息是否到达,但它并不处理这个消息,所以调度器还会进一步将消息传递给后续的流程。 比如,下面的两个事务,事务 2 和事务 1 相比,只是多了一个主动发起的请求,以及等对方回应命令的时间约束。

_images/event-1.png _images/event-2.png

这种情况下,事务 2 所描述的过程事实上是个可复用的整体。但是,由于事务 1 中的那个定时器约束的是从请求发出到命令到达的时间。 所以,你很难从已有的手段中找到一种优雅简洁的表达来进行复用。

而借助于 __peek ,这个问题就迎刃而解。

__def(Trans2) __as
( __sync(Action2)
, __asyn(Action3));

__transaction
( __time_guard
    ( TIMER_1
    , __sync(Action1)
    , __peek(EV_FOO))
, __apply(Trans2));

__transaction
( __apply(Trans2) );

并不难看出, __peek__wait 的唯一差别是, __wait 会把消息吃掉,而 __peek 则只看一眼, 然后把消息留给后续的操作。