Azure Service Fabric中的发布/订阅模式

20
我正在开发一个 Azure Service Fabric 应用程序,其中有一些演员需要根据需求接收来自其他服务的 ping/hook。该应用程序是一种事件分发引擎,旨在像这样工作:
- 可以接收事件并负责将该事件分发给该事件类型的所有订阅者的事件路由器演员。 - 0..N个事件订阅演员,它们需要以某种方式通知路由器它们希望订阅哪种类型的事件以及它们希望如何交付它们(同步还是异步)。 - 当事件路由器演员接收到类型为 MyEvent 的事件时,它将确定哪些订阅者正在侦听以及它们希望如何交付事件。对于异步交付,消息将在 Azure Service Bus 主题中弹出。但是对于同步交付,路由器演员将直接调用订阅演员的订阅方法,并等待其响应。
大部分都很简单,但我不太确定如何实现这些事件的同步交付。我不希望事件路由器演员以任何方式了解订阅事件的演员的任何内部情况,但是使用当前的 ActorProxy 实现和类似内容,需要访问接口才能在其他演员上调用方法。
假设我订阅了一个事件类型,通知事件路由器我的地址是 fabric:/MyApp/MyEventSubscriberActor,并且我想订阅 MyEvent。在 Service Fabric APIs 中,是否有明智的方法可以编程地在那个演员上调用方法而无需使用 ActorProxy.Create<IMyEventSubscriberActor>() 方法(例如 OnEventAsync(MyEvent ev))?这些 API 的源代码似乎不是公开可用的,因此我没有直接检查其工作原理的方法。

我有点好奇为什么你想要同时进行同步和异步,除非有一些事件需要路由到不同的应用程序并发送到Azure Service Bus主题。我还观察到,制作一个发布/订阅模式对于可扩展性没有帮助,因为路由器角色会被阻塞,直到订阅者角色完成任务。你有考虑过“fire and forget”吗?在这种情况下,订阅者角色从ReliableQueue中获取事件。 - wonderful world
其实我自己也考虑了一下这个问题;我想,我只需要在所有地方进行同步事件传递,然后由订阅者自己确定是否立即处理事件,还是将其弹出 ReliableQueue 进行异步处理。谢谢您的建议。 - Trond Nordheim
我认为使用“发射并忘记”的异步方法,与同步方式相比,您可以处理更多的事件。 - wonderful world
1个回答

29

事件订阅演员可以实现包含“event-available”方法的事件订阅接口。它可以将该接口传递给事件路由器演员接口上的“subscribe-to-event”方法。

事件路由器演员接口可以将订阅接口作为其状态的一部分保留引用。当订阅者感兴趣的事件发生时,它可以调用先前收到并保存的接口上的“event-available”方法。所有这些都可以在不显式创建演员代理以与事件订阅演员通信的情况下完成(演员序列化基础架构在幕后执行此操作)。

以下是一个非常基本的示例,省略了事件类型,假设只有一个订阅者等,但应该可以让您了解该技术的思想。

接口:

interface IEventRouter : IActor
{
    void Subscribe(IEventSubscriber subscriber);
}

interface IEventSubscriber : IActor
{
    void EventAvailable();
}

Event subscriber code:

事件订阅者代码:
class EventSubscriber : Actor, IEventSubscriber
{
    void SubscribeToEvent()
    {
        IEventRouter router = ActorProxy.Create<IEventRouter>("fabric:/MyApp/MyEventRouterActor");
        router.Subscribe(this);
    }

    public void EventAvailable()
    {
        // Process the event
    }
}

事件路由器代码:

// Define actor state
[DataContract]
class RouterState
{
    [DataMember]
    public IEventSubscriber Subscriber;
}

// Define actor
class EventRouter : Actor<RouterState>, IEventRouter
{
    public void Subscribe(IEventSubscriber subscriber)
    {
        this.State.Subscriber = subscriber;
    }

    void OnEventAvailable()
    {
        this.State.Subscriber.EventAvailable();
    }
}       

1
哇,这实际上相当优雅,而且是我没有想到的。我的思维非常局限于一个接口意味着一个参与者的想法;为此目的在多个参与者类型之间重用接口甚至没有跨越我的脑海。感谢您的输入,这可能会很好地解决问题。 - Trond Nordheim
7
知道序列化基础设施处理接口到Actor代理映射非常有帮助。谢谢!这使得我原本担心的情况容易多了 - Lars Kemmann
2
你可以使用这个NuGet包ServiceFabric.PubSubActors来实现发布/订阅引擎/框架。代码可在GitHub上找到:https://github.com/loekd/ServiceFabric.PubSubActors - alltej
如果IEventRouter是一个服务,这个例子也能工作吗?我得到了ActorProxy无法序列化的异常。 - Poul K. Sørensen

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接