3

我在为工作项目实施正确的模式时遇到了一些麻烦,在我对正确的设计策略感到满意之前,我不想先行。

该项目基于Genesys 计算机电话集成 (CTI) 平台。本质上,利用 Genesys 提供的 SDK,单个客户端可以订阅多个远程运行的 Genesys 服务(或TServer)。客户端然后注册与特定TServer相关联的一整堆目录号码 (DN)并等待呼叫事件。当事件发生时,它被客户端捕获并存储在数据库中。执行了许多其他操作,这在此阶段无关紧要。许多通信工作由 Genesys ProtocolManager对象处理,因此单个事件处理程序捕获所有客户端的事件数据,而这些数据又由EventBrokerService处理. 下面是一个简单的代码来说明连接过程、单个DN的注册和事件函数:

        EventBrokerService eventBrokerService;

        using (var client = new TServerProtocol(
            new Endpoint(
                new Uri("tcp://tserver01:11234"))))
        {
            client.Open();

            eventBrokerService = BrokerServiceFactory.CreateEventBroker(client);
            eventBrokerService.Activate();
            eventBrokerService.Register(this.OnEvent);

            RequestRegisterAddress requestRegisterAddress = 
                    RequestRegisterAddress.Create("977845873", 
                                                  RegisterMode.ModeMonitor, 
                                                  ControlMode.RegisterDefault, 
                                                  AddressType.DN);
            IMessage response = client.Request(requestRegisterAddress);
        }

然后我们监听事件(有很多不同的事件):

    private void OnEvent(IMessage response)
    {
        switch (response.Id)
        {
            case EventACK.MessageId:
                //do something
                break;
            case EventLinkConnected.MessageId:
                var ev = response as EventLinkConnected;
                //Insert event into DB and perform some other operations...
                break;
        }
    }

Genesys 平台附带另一个称为 Genesys 配置服务器的组件。配置服务器保存所有 TServer 详细信息,包括 DN 信息和一大堆其他“对象”。它实际上只是一个花哨的 DBMS。不同之处在于,您还可以订阅配置服务器并注册 CRUD 事件(即CreateEventUpdateEvent等...)。没有说明代码,概念与上面的类似。(即您可以注册到多个不同的配置服务器并监听 CRUD 事件)。

在大多数情况下,我已经很好地涵盖了上述内容,并且我对迄今为止的实施感到满意。我想要实现的目标如下:

我正在尝试实现一个分布式系统。简而言之,该系统将由 2 个组件组成。监控服务和调度服务组件(它们都将是 Windows 服务)

监控服务组件

  • “监控服务”连接到 1 个或多个 T 服务器以监控呼叫事件
  • 监控服务也将订阅调度服务

调度服务组件

  • “调度程序服务”连接到 1 个或多个配置服务器并等待 CRUD 事件。
  • 一旦事件发生(即在配置服务器上添加了一个新的DN),调度程序捕获创建事件,并通知所有监控服务订阅者。随后,调度程序还将更新本地数据库,因此保留 DN 信息以备冗余(以防调度程序无法连接到配置服务器)。
  • 新创建的 DN 所属的监视订阅者(由唯一的 DBID 和 TServerID 标识符区分)将接受 DN,并将其注册用于侦听事件(类似于第一个代码片段中所示)。不具备所需 TServer 连接的监控订阅者自然会丢弃接收到的请求。
  • Dispatcher 也可以接收新添加的 TServer,但这一次,它将决定要使用哪个监控服务,以便该监控服务建立另一个连接。这将取决于诸如监视服务上运行的当前会话数或单个服务当时正在消耗多少内存等因素。

我提出了一些基本概念,下面是一些代码来说明我到目前为止所做的事情:

我选择的通信方式是 WCF 和NetTcpBinding,所以对于简单的部分,我暴露了一个接口:

[ServiceContract(Namespace = "urn:Netwatch", 
                 SessionMode = SessionMode.Required, 
                 CallbackContract = typeof(IDisMonServiceCallback))]
public interface IDisMonService
{
    [OperationContract]
    bool Subscribe(string uid);
    [OperationContract(IsOneWay = true)]
    void Unsubscribe(string uid);
}

[ServiceContract(Namespace="urn:Netwatch")]
public interface IDisMonServiceCallback
{
    [OperationContract]
    bool DNRegistered(int tServerId, string dnEntry);
}

在调度程序上,我已经实现了它:

    [ServiceBehavior(InstanceContextMode = InstanceContextMode.Single, ConcurrencyMode = ConcurrencyMode.Multiple)]
public class DisMonService : IDisMonService
{
    private ConcurrentDictionary<string, IDisMonServiceCallback> subscribers = new ConcurrentDictionary<string, IDisMonServiceCallback>();

    public IDisMonServiceCallback this[string uid]
    {
        get
        {
            IDisMonServiceCallback callback;
            if (!subscribers.TryGetValue(uid, out callback))
                return null;
            return callback;
        }
    }

    public List<IDisMonServiceCallback> GetAllServiceCallbacks()
    {
        return new List<IDisMonServiceCallback>(subscribers.Values);
    }

    public bool Subscribe(string uid)
    {
        IDisMonServiceCallback callback = GlobalHelper.Callback<IDisMonServiceCallback>();

        if (!subscribers.ContainsKey(uid))
            if (!subscribers.TryAdd(uid, callback))
                return false;
        return true;
    }

    public void Unsubscribe(string uid)
    {
        IDisMonServiceCallback callback;

        if (subscribers.ContainsKey(uid))
            if (!subscribers.TryRemove(uid, out callback))
                return;
        return;
    }
}

从上面的代码中,很明显每个订阅的监控服务都有一个唯一的标识符,这样就可以检索到正确的服务回调上下文(以防我决定做一些其他时髦的操作)。

这就是我的困境基本上开始的地方。长话短说,我的问题如下:

  1. 尝试从 Dispatcher 服务中将消息传递给所有订阅者时,如何处理DisMonService类。即添加了新的DN,让我们调用DisMonService类并通知所有订阅者。
  2. 在DisMonServie中处理所有订阅者的更新时,实现的最佳模式是什么

目前,我的虚拟客户端连接到调度程序,并且它自己注册。展望未来,访问DisMonService类的最佳方式是什么。

我希望我不会让任何人对我要问的问题感到困惑。我想我真正想要找到的是实现上述系统的最佳方法,任何建议等等。一些代码示例和片段真的很有帮助。

这是我在这里的第一篇文章,所以如果我没有按照论坛的标准解释自己,我向任何人道歉。

4

0 回答 0