Reliable Services 通知Reliable Services notifications

通知可让客户端跟踪对它们感兴趣的对象所进行的更改。Notifications allow clients to track the changes that are being made to an object that they're interested in. 有两种类型的对象支持通知:可靠状态管理器 和可靠字典 。Two types of objects support notifications: Reliable State Manager and Reliable Dictionary.

使用通知的常见原因如下:Common reasons for using notifications are:

  • 生成副本状态的具体化视图(例如次要索引)或聚合筛选视图。Building materialized views, such as secondary indexes or aggregated filtered views of the replica's state. 可靠字典中所有键的排序索引便是其中一个例子。An example is a sorted index of all keys in Reliable Dictionary.
  • 发送监视数据,例如过去一小时内添加的用户数目。Sending monitoring data, such as the number of users added in the last hour.

通知会在应用操作的过程中触发。Notifications are fired as part of applying operations. 因此,应该尽快处理通知,且同步事件不应包含任何耗费资源的操作。Because of that, notifications should be handled as fast as possible, and synchronous events shouldn't include any expensive operations.

可靠状态管理器通知Reliable State Manager notifications

可靠状态管理器为以下事件提供通知:Reliable State Manager provides notifications for the following events:

  • 事务Transaction
    • 提交Commit
  • 状态管理器State manager
    • 重新生成Rebuild
    • 添加可靠状态Addition of a reliable state
    • 删除可靠状态Removal of a reliable state

可靠状态管理器会跟踪当前正在进行的事务。Reliable State Manager tracks the current inflight transactions. 唯一会导致通知触发的事务状态更改是提交事务。The only change in transaction state that causes a notification to be fired is a transaction being committed.

可靠状态管理器会维护可靠状态的集合,例如可靠字典和可靠队列。Reliable State Manager maintains a collection of reliable states like Reliable Dictionary and Reliable Queue. 可靠状态管理器会在此集合更改时触发通知:添加或删除可靠状态,或者重新生成整个集合时。Reliable State Manager fires notifications when this collection changes: a reliable state is added or removed, or the entire collection is rebuilt. 可靠状态管理器集合会在以下三种情况下重新生成:The Reliable State Manager collection is rebuilt in three cases:

  • 恢复:当副本启动时,它会从磁盘恢复其先前的状态。Recovery: When a replica starts, it recovers its previous state from the disk. 恢复结束时,它会使用 NotifyStateManagerChangedEventArgs 触发事件,其中包含一组已恢复的可靠状态。At the end of recovery, it uses NotifyStateManagerChangedEventArgs to fire an event that contains the set of recovered reliable states.
  • 完整副本:必须先生成副本,然后它才能加入配置集。Full copy: Before a replica can join the configuration set, it has to be built. 有时,这需要将主要副本中可靠状态管理器状态的完整副本应用到空闲的次要副本。Sometimes, this requires a full copy of Reliable State Manager's state from the primary replica to be applied to the idle secondary replica. 次要副本上的可靠状态管理器会使用 NotifyStateManagerChangedEventArgs 触发事件,其中包含一组它从主要副本获取的可靠状态。Reliable State Manager on the secondary replica uses NotifyStateManagerChangedEventArgs to fire an event that contains the set of reliable states that it acquired from the primary replica.
  • 还原:在灾难恢复方案中,副本的状态可通过 RestoreAsync 从备份还原。Restore: In disaster recovery scenarios, the replica's state can be restored from a backup via RestoreAsync. 在这种情况下,主要副本上的可靠状态管理器会使用 NotifyStateManagerChangedEventArgs 触发事件,其中包含一组它从备份还原的可靠状态。In such cases, Reliable State Manager on the primary replica uses NotifyStateManagerChangedEventArgs to fire an event that contains the set of reliable states that it restored from the backup.

若要注册事务通知和/或状态管理器通知,需要在可靠状态管理器上注册 TransactionChangedStateManagerChanged 事件。To register for transaction notifications and/or state manager notifications, you need to register with the TransactionChanged or StateManagerChanged events on Reliable State Manager. 注册这些事件处理程序的常见位置是有状态服务的构造函数。A common place to register with these event handlers is the constructor of your stateful service. 在构造函数上注册时,也不会错过 IReliableStateManager 生存期内的更改所导致的任何通知。When you register on the constructor, you won't miss any notification that's caused by a change during the lifetime of IReliableStateManager.

public MyService(StatefulServiceContext context)
    : base(MyService.EndpointName, context, CreateReliableStateManager(context))
{
    this.StateManager.TransactionChanged += this.OnTransactionChangedHandler;
    this.StateManager.StateManagerChanged += this.OnStateManagerChangedHandler;
}

TransactionChanged 事件处理程序使用 NotifyTransactionChangedEventArgs 来提供有关事件的详细信息。The TransactionChanged event handler uses NotifyTransactionChangedEventArgs to provide details about the event. 它包含用于指定更改类型的操作属性(例如,NotifyTransactionChangedAction.Commit)。It contains the action property (for example, NotifyTransactionChangedAction.Commit) that specifies the type of change. 也包含提供对已更改事务的引用的事务属性。It also contains the transaction property that provides a reference to the transaction that changed.

备注

现在,只有提交事务才会引发 TransactionChanged 事件。Today, TransactionChanged events are raised only if the transaction is committed. 此操作等同于 NotifyTransactionChangedAction.CommitThe action is then equal to NotifyTransactionChangedAction.Commit. 但是在未来,可能会有其他类型的事务状态更改可以引发事件。But in the future, events might be raised for other types of transaction state changes. 建议检查操作,仅在预期的事件发生时处理事件。We recommend checking the action and processing the event only if it's one that you expect.

以下是 TransactionChanged 事件处理程序示例。Following is an example TransactionChanged event handler.

private void OnTransactionChangedHandler(object sender, NotifyTransactionChangedEventArgs e)
{
    if (e.Action == NotifyTransactionChangedAction.Commit)
    {
        this.lastCommitLsn = e.Transaction.CommitSequenceNumber;
        this.lastTransactionId = e.Transaction.TransactionId;

        this.lastCommittedTransactionList.Add(e.Transaction.TransactionId);
    }
}

StateManagerChanged 事件处理程序使用 NotifyStateManagerChangedEventArgs 来提供有关事件的详细信息。The StateManagerChanged event handler uses NotifyStateManagerChangedEventArgs to provide details about the event. NotifyStateManagerChangedEventArgs 有两个子类:NotifyStateManagerRebuildEventArgsNotifyStateManagerSingleEntityChangedEventArgsNotifyStateManagerChangedEventArgs has two subclasses: NotifyStateManagerRebuildEventArgs and NotifyStateManagerSingleEntityChangedEventArgs. 使用 NotifyStateManagerChangedEventArgs 中的操作属性将 NotifyStateManagerChangedEventArgs 转换为正确的子类:You use the action property in NotifyStateManagerChangedEventArgs to cast NotifyStateManagerChangedEventArgs to the correct subclass:

  • NotifyStateManagerChangedAction.RebuildNotifyStateManagerRebuildEventArgsNotifyStateManagerChangedAction.Rebuild: NotifyStateManagerRebuildEventArgs
  • NotifyStateManagerChangedAction.AddNotifyStateManagerChangedAction.RemoveNotifyStateManagerSingleEntityChangedEventArgsNotifyStateManagerChangedAction.Add and NotifyStateManagerChangedAction.Remove: NotifyStateManagerSingleEntityChangedEventArgs

以下是 StateManagerChanged 通知处理程序示例。Following is an example StateManagerChanged notification handler.

public void OnStateManagerChangedHandler(object sender, NotifyStateManagerChangedEventArgs e)
{
    if (e.Action == NotifyStateManagerChangedAction.Rebuild)
    {
        this.ProcessStateManagerRebuildNotification(e);

        return;
    }

    this.ProcessStateManagerSingleEntityNotification(e);
}

可靠字典通知Reliable Dictionary notifications

可靠字典为以下事件提供通知:Reliable Dictionary provides notifications for the following events:

  • 重新生成:在 ReliableDictionary 从过去恢复或复制的本地状态或备份恢复其状态后调用。Rebuild: Called when ReliableDictionary has recovered its state from a recovered or copied local state or backup.
  • 清除:在通过 ClearAsync 方法清除 ReliableDictionary 的状态后调用。Clear: Called when the state of ReliableDictionary has been cleared through the ClearAsync method.
  • 添加:在向 ReliableDictionary 添加项之后调用。Add: Called when an item has been added to ReliableDictionary.
  • 更新:在更新 IReliableDictionary 中的项后调用。Update: Called when an item in IReliableDictionary has been updated.
  • 删除:在删除 IReliableDictionary 中的项之后调用。Remove: Called when an item in IReliableDictionary has been deleted.

若要获取可靠字典通知,需在 DictionaryChanged 上注册 IReliableDictionary 事件处理程序。To get Reliable Dictionary notifications, you need to register with the DictionaryChanged event handler on IReliableDictionary. 注册这些事件处理程序的常见位置是在 ReliableStateManager.StateManagerChanged 添加通知中。A common place to register with these event handlers is in the ReliableStateManager.StateManagerChanged add notification. 在将 IReliableDictionary 添加到 IReliableStateManager 时注册,可确保不会错过任何通知。Registering when IReliableDictionary is added to IReliableStateManager ensures that you won't miss any notifications.

private void ProcessStateManagerSingleEntityNotification(NotifyStateManagerChangedEventArgs e)
{
    var operation = e as NotifyStateManagerSingleEntityChangedEventArgs;

    if (operation.Action == NotifyStateManagerChangedAction.Add)
    {
        if (operation.ReliableState is IReliableDictionary<TKey, TValue>)
        {
            var dictionary = (IReliableDictionary<TKey, TValue>)operation.ReliableState;
            dictionary.RebuildNotificationAsyncCallback = this.OnDictionaryRebuildNotificationHandlerAsync;
            dictionary.DictionaryChanged += this.OnDictionaryChangedHandler;
        }
    }
}

备注

ProcessStateManagerSingleEntityNotification 是上述 OnStateManagerChangedHandler 示例所调用的示例方法。ProcessStateManagerSingleEntityNotification is the sample method that the preceding OnStateManagerChangedHandler example calls.

上述代码会设置 IReliableNotificationAsyncCallback 接口以及 DictionaryChangedThe preceding code sets the IReliableNotificationAsyncCallback interface, along with DictionaryChanged. 由于 NotifyDictionaryRebuildEventArgs 包含需要以异步方式枚举的 IAsyncEnumerable 接口,因此会通过 RebuildNotificationAsyncCallback 而不是 OnDictionaryChangedHandler 来触发重新生成通知。Because NotifyDictionaryRebuildEventArgs contains an IAsyncEnumerable interface--which needs to be enumerated asynchronously--rebuild notifications are fired through RebuildNotificationAsyncCallback instead of OnDictionaryChangedHandler.

public async Task OnDictionaryRebuildNotificationHandlerAsync(
    IReliableDictionary<TKey, TValue> origin,
    NotifyDictionaryRebuildEventArgs<TKey, TValue> rebuildNotification)
{
    this.secondaryIndex.Clear();

    var enumerator = e.State.GetAsyncEnumerator();
    while (await enumerator.MoveNextAsync(CancellationToken.None))
    {
        this.secondaryIndex.Add(enumerator.Current.Key, enumerator.Current.Value);
    }
}

备注

在上述代码中,在处理重新生成通知的过程中,会先清除所维护的聚合状态。In the preceding code, as part of processing the rebuild notification, first the maintained aggregated state is cleared. 由于正在利用新状态重新生成可靠集合,因此与以前的所有通知不相关。Because the reliable collection is being rebuilt with a new state, all previous notifications are irrelevant.

DictionaryChanged 事件处理程序使用 NotifyDictionaryChangedEventArgs 来提供有关事件的详细信息。The DictionaryChanged event handler uses NotifyDictionaryChangedEventArgs to provide details about the event. NotifyDictionaryChangedEventArgs 有五个子类。NotifyDictionaryChangedEventArgs has five subclasses. 使用 NotifyDictionaryChangedEventArgs 中的操作属性将 NotifyDictionaryChangedEventArgs 转换为正确的子类:Use the action property in NotifyDictionaryChangedEventArgs to cast NotifyDictionaryChangedEventArgs to the correct subclass:

  • NotifyDictionaryChangedAction.RebuildNotifyDictionaryRebuildEventArgsNotifyDictionaryChangedAction.Rebuild: NotifyDictionaryRebuildEventArgs
  • NotifyDictionaryChangedAction.ClearNotifyDictionaryClearEventArgsNotifyDictionaryChangedAction.Clear: NotifyDictionaryClearEventArgs
  • NotifyDictionaryChangedAction.AddNotifyDictionaryItemAddedEventArgsNotifyDictionaryChangedAction.Add: NotifyDictionaryItemAddedEventArgs
  • NotifyDictionaryChangedAction.UpdateNotifyDictionaryItemUpdatedEventArgsNotifyDictionaryChangedAction.Update: NotifyDictionaryItemUpdatedEventArgs
  • NotifyDictionaryChangedAction.RemoveNotifyDictionaryItemRemovedEventArgsNotifyDictionaryChangedAction.Remove: NotifyDictionaryItemRemovedEventArgs
public void OnDictionaryChangedHandler(object sender, NotifyDictionaryChangedEventArgs<TKey, TValue> e)
{
    switch (e.Action)
    {
        case NotifyDictionaryChangedAction.Clear:
            var clearEvent = e as NotifyDictionaryClearEventArgs<TKey, TValue>;
            this.ProcessClearNotification(clearEvent);
            return;

        case NotifyDictionaryChangedAction.Add:
            var addEvent = e as NotifyDictionaryItemAddedEventArgs<TKey, TValue>;
            this.ProcessAddNotification(addEvent);
            return;

        case NotifyDictionaryChangedAction.Update:
            var updateEvent = e as NotifyDictionaryItemUpdatedEventArgs<TKey, TValue>;
            this.ProcessUpdateNotification(updateEvent);
            return;

        case NotifyDictionaryChangedAction.Remove:
            var deleteEvent = e as NotifyDictionaryItemRemovedEventArgs<TKey, TValue>;
            this.ProcessRemoveNotification(deleteEvent);
            return;

        default:
            break;
    }
}

建议Recommendations

  • 尽快完成通知事件。Do complete notification events as fast as possible.
  • 不要执行任何耗费资源的操作(例如 I/O 操作)作为同步事件的一部分。Do not execute any expensive operations (for example, I/O operations) as part of synchronous events.
  • 处理事件之前,先检查操作类型。Do check the action type before you process the event. 未来可能会添加新的操作类型。New action types might be added in the future.

需谨记以下几点:Here are some things to keep in mind:

  • 通知会在执行操作的过程中触发。Notifications are fired as part of the execution of an operation. 例如,在还原操作的最后一个步骤触发还原通知。For example, a restore notification is fired as the last step of a restore operation. 处理通知事件之前,不会完成还原。A restore will not finish until the notification event is processed.
  • 由于通知会在应用操作的过程中触发,因此,客户端只会看见本地提交操作的通知。Because notifications are fired as part of the applying operations, clients see only notifications for locally committed operations. 而且因为操作只保证会在本地提交(亦即记录),所以它们不一定可在未来恢复。And because operations are guaranteed only to be locally committed (in other words, logged), they might or might not be undone in the future.
  • 在恢复路径上,会针对每个应用的操作触发单个通知。On the redo path, a single notification is fired for each applied operation. 这表示,如果事务 T1 包含 Create(X)、Delete(X) 和 Create(X),你将依次收到一个针对 X 创建的通知,一个针对删除的通知,此后再收到一个针对创建的通知。This means that if transaction T1 includes Create(X), Delete(X), and Create(X), you'll get one notification for the creation of X, one for the deletion, and one for the creation again, in that order.
  • 对于包含多个操作的事务,操作按用户在主要副本上收到它们的顺序应用。For transactions that contain multiple operations, operations are applied in the order in which they were received on the primary replica from the user.
  • 在处理错误进度的过程中,某些操作可能会恢复。As part of processing false progress, some operations might be undone. 通知会针对这类恢复操作加以触发,将副本状态回滚到稳定的时间点。Notifications are raised for such undo operations, rolling the state of the replica back to a stable point. 恢复通知的一个重要区别,是具有重复键的事件会聚合在一起。One important difference of undo notifications is that events that have duplicate keys are aggregated. 例如,如果恢复事务 T1,可以看到一条针对 Delete(X) 的通知。For example, if transaction T1 is being undone, you'll see a single notification to Delete(X).

后续步骤Next steps