作業プロジェクトに適切なパターンを実装するのに問題があり、適切な設計戦略に満足するまで先に進みたくありません。
このプロジェクトは、Genesys Computer Telephony Integration(CTI)プラットフォームに基づいています。基本的に、Genesysが提供するSDKを利用して、単一のクライアントがリモートで実行されている多数のGenesysサービス(またはTServer)にサブスクライブします。次に、クライアントは特定のTServerに関連付けられた電話番号(DN)のヒープ全体を登録し、呼び出しイベントを待ちます。イベントが発生すると、クライアントによってキャプチャされ、データベースに保存されます。他の多くの操作が実行されますが、この段階では関係ありません。多くの通信作業はGenesysProtocolManagerオブジェクトによって処理されるため、単一のイベントハンドラーがすべてのクライアントのイベントデータをキャプチャし、それが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構成サーバーと呼ばれる別のコンポーネントが付属しています。構成サーバーは、DN情報やその他の「オブジェクト」全体を含む、TServerのすべての詳細を保持します。それは本当にただの派手なDBMSです。違いは、構成サーバーにサブスクライブしてCRUDイベント(つまり、 CreateEvent、UpdateEventなど)に登録することもできることです。コードを説明しない限り、概念は上記と同様です。(つまり、さまざまな構成サーバーに登録して、CRUDイベントをリッスンできます)。
ほとんどの場合、私は上記を十分にカバーしており、これまでの実装に満足しています。私が達成しようとしていることは次のとおりです。
分散システムを実装しようとしています。一言で言えば、システムは2つのコンポーネントで構成されます。監視サービスおよびディスパッチャサービスコンポーネント(これらはすべてWindowsサービスになります)
監視サービスコンポーネント
- 「監視サービス」は、1つまたは複数のTサーバーに接続して、通話イベントを監視します
- 監視サービスは、ディスパッチャサービスにもサブスクライブします
ディスパッチャサービスコンポーネント
- 「ディスパッチャサービス」は、1つ以上の構成サーバーに接続し、CRUDイベントを待機します。
- イベントが発生すると(つまり、構成サーバーに新しいDNが追加されると)、ディスパッチャーは作成イベントをキャプチャし、すべての監視サービスサブスクライバーに通知します。その後、ディスパッチャはローカルデータベースも更新するため、DN情報は冗長性のために保持されます(ディスパッチャが構成サーバーに接続できない場合)。
- 新しく作成されたDNが属する(一意のDBIDおよびTServerID識別子によって区別される)監視サブスクライバーは、DNを受け入れ、リスニングイベントに登録します(最初のコードスニペットに同様に示されています)。必要なTServer接続を持たない監視サブスクライバーは、当然、受信した要求をドロップします。
- ディスパッチャは、新しく追加されたTServerを受信することもできますが、今回は、その監視サービスが別の接続を確立するために、どの監視サービスを利用するかを決定します。これは、監視サービスで実行されている現在のセッションの数や、単一のサービスがその時点で咀嚼しているメモリの量などの要因によって決まります。
私はいくつかの基本的な概念を考え出しました。これまでに行ったことを説明するためのコードをいくつか示します。
私が選択した通信方法は、NetTcpBindingを使用したWCFであるため、単純な部分として、インターフェイスを公開しました。
[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;
}
}
上記のコードから、サブスクライブしている各監視サービスが一意の識別子を持っていることは明らかです。これにより、適切なサービスコールバックコンテキストが取得されます(他のファンキーな操作を行うことにした場合)。
これが私のジレンマが本質的に始まるところです。長い話を短くするために、私の質問は次のとおりです。
- Dispatcherサービス内からすべてのサブスクライバーにメッセージを渡そうとするときにDisMonServiceクラスを処理するにはどうすればよいですか。つまり、新しいDNが追加されたので、DisMonServiceクラスを呼び出して、すべてのサブスクライバーに通知します。
- DisMonServie内からすべてのサブスクライバーへの更新を処理する際に実装するのに最適なパターンは何でしょうか
現時点では、ダミークライアントがディスパッチャに接続し、それ自体が登録されています。今後、DisMonServiceクラスにアクセスするための最良の方法は何ですか。
私が尋ねようとしていることで誰かを混乱させないことを願っています。私が本当に見つけようとしているのは、上記のシステムや提案などを実装するための最良の方法だと思います。いくつかのコードサンプルとスニペットは本当に役に立ちます。
これは私の最初の投稿ですので、フォーラムの基準について説明していなかった場合は、誰にでもお詫び申し上げます。