I apologize in advance for a long-read question, but i'm hardly stuck here and don`t how to ask for help using fewer words.
I need to implement a middleware service which should be placed between two big systems: First - Asterisk virtual telephony station; Second - our company enterprise core.
Enterprise core consist from many instances of CoreServer. They all considered to be the same (duplicates) Asterisk considered to be a singleton system.
So I need to implement a service that must be kind a bridge/access window between many CoreServers and single Aster. Lets call it AsterService.
Restrictions:
- Part that should be inside CoreServer can be written using Net Framework 4.5.2 maximum! So such technologies like gRPS can't be used.
- Generally Microsoft tech stack, no containers. So no Kafka, RabbitMQ and etc is allowed.
That explains why I choosed WCF for implementing this service.
Service must provide next features:
1) Base communication between systems. For example, sending commands from core to Aster and getting data from Asterisk database.
2) Observe and store current state of Aster server (queues, active calls, members etc.)
3) Monitoring that state. Here the intersting point is that each CoreServer serves many clients. Each client may want to obsreve some concrete of Aster state (queues list or queue members or active channels list etc)
Let's discuss each of them:
1) This part is OK, no questions. I have a good interface for interacting with Asterisk for getting data from it or sending commands to it. I'm using AsterNET if someone's interested. Other parts are not so clear for me and want to discuss each of them.
2) Observing and storing Aster state
Ok, I have all necessary functional for this regarding to interaction with Aster. I can get queues, it's members, I receive all events if, for example, new active channel is created. This should be a singleton, that holds one connection to Aster, observes it's events and provide a channel for sending commands to it. Of course, I can store all this data in some data collections, which always evolve reflecting all changes in Aster state. Let's call this part AsterMonitor.
The problem is how to make properly interaction between WCF service and this singleton part that observes Aster state?
As I understand for WCF the best way is to implement perCall InstanceContextMode, not single. So where I should keep my AsterMonitor? I can't store it inside WCF without using Single instance mode. (currently I'm using single, but I want to change it to PerCall or PerSession, keeping AsterService lightweight)
Should this AsterMonitor be a separate service with its own interface for AsterService? Maybe, but it's hard to maintain, because both of them are always evolving.
Maybe there is a better way to make it like system service, keeping it singleton, allowing to interact with it directly through shared memory without maintaining WCF interfaces and all it's structure?
3) Providing access for Aster state data
The problem is that behind each CoreServer can be many clients. Each client may want to observe his concrete point of interest. For example members list of concrete queue.
First idea is to store a copy of Aster state in each CoreServer, so clients will interact with CoreServer. Bad idea, because:
- our CoreServers instances are really overloaded by other functionality. We to need to reduce load from them.
- Clients interacr with CoreServer via Remoting. If so, we need to implement some extra layer.
- We can connect clients directly to our AsterService, leaving CoreServers separate from all this kitchen.
Ok, all our clients, who are interested in interacting with Aster, can interact directly with our AsterService through WCF. Appears next problem: How to send data to all the clients? Aster state is pretty big array of data and each client is interested only in 1% of this data. More, many clients can be interested in same data type, but with different Ids. For example, two clients, who observe member list of two different queues. So we need something like Observer/Publisher pattern.
Sounds good, but:
- AsterMonitor consists from many separate objects - Monitors. Each monitor observes it's part of state and provides it's own pack of operations to get that data. If we'll try to put that all in our AsterService interface - it turns into disaster. It's very hardly maintanable. Especially keeping in mind, that we want to keep AsterService lightweight and AsterMonitor singleton.
- We should not send changed data to all the clients, only for those who are interested.
Ok, let's try to create a tiny message broker between client and AsterService. Each Monitor inside AsterMonitor can publish kind a message inside AsterService Host. AsterService provides functionality to subscribe\unsubsribe for some messages, keeping inside of it list of subscribers and resending those messages only to clients who subscribed.
It works somehow, but also turns into disaster in maintaining. Especially trying to implement ability to subscribe to concrete objects with it's own Id. Especially without ability to transmit generic classes.
How to implement ability to subscribe\unsubscribe to topics and concrete objects? I have next thoughts about it:
- Switch to messaging in JSON
- Intergrate those monitors in ASterService using MEF, But have no idea how to it.
- Implement one big AsterMonitor service. For client interacting with every type of monitor implement separate tiny AsterService. Like AsterService_QueueMonitor, AsterService_ActiveCallsMonitor.
I will appreciate any ideas about this problem.