I implemented an observer pattern using events and delegates. The program is receiving and processing big amounts of data (around 3000 messages per second) but at some point, it starts sending messages with a delayed timestamp, which I am trying to fix. I have 3 main classes that do the job in my opinion:
public class MessageTracker : IObservable<MessageEventArgs>
{
private List<IObserver<MessageEventArgs>> observers;
public MessageTracker()
{
observers = new List<IObserver<MessageEventArgs>>();
}
private static readonly MessageTracker mInstance = new MessageTracker();
private static MessageTracker getInstance() => mInstance;
private class Unsubscriber : IDisposable
{
private List<IObserver<MessageEventArgs>> _observers;
private IObserver<MessageEventArgs> _observer;
public Unsubscriber(List<IObserver<MessageEventArgs>> observers, IObserver<MessageEventArgs> observer)
{
this._observers = observers;
this._observer = observer;
}
public void Dispose()
{
if (! (_observer == null)) _observers.Remove(_observer);
}
}
public IDisposable Subscribe(IObserver<MessageEventArgs> observer)
{
if (! observers.Contains(observer))
observers.Add(observer);
return new Unsubscriber(observers, observer);
}
public void MessageTrack(MessageEventArgs msg) {
observers.AsParallel().ForAll(observer =>
{
if (msg is null)
observer.OnError(new ArgumentException("MessageError."));
else
observer.OnNext(msg);
});
}
public void EndMessageTrans(){
foreach(var observer in observers.ToArray())
if (observers.Contains(observer))
observer.OnCompleted();
observers.Clear();
}
}
public class MessageReporter : IObserver<MessageEventArgs>
{
private IDisposable unsubscriber;
public MessageReporter()
{ }
public event EventHandler<MessageEventArgs> OnNextMessage;
public virtual void Subscribe(IObservable<MessageEventArgs> provider)
{
if (provider != null)
unsubscriber = provider.Subscribe(this);
}
public void OnCompleted()
{
this.Unsubscribe();
}
public void OnError(Exception error)
{
}
public void OnNext(MessageEventArgs value)
{
if (OnNextMessage != null)
{
OnNextMessage?.Invoke(this, value);
}
}
public virtual void Unsubscribe()
{
unsubscriber.Dispose();
}
}
public sealed class MessageDataWorker
{
private readonly bool mSubscribeAll;
private readonly IEnumerable<string> mMessages;
public MessageDataWorker(IEnumerable<string> messages)
{
mMessages = messages;
if ((mMessages?.Count() ?? 0) == 0)
mSubscribeAll = true;
}
public override void DoWork()
{
var messageReporter = new MessageReporter();
messageReporter.OnNextMessage += OnNewMessageReceived;
messageReporter.Subscribe(MessageTracker.GetInstance());
while (!mShouldStop.WaitOne(100)) ;
MessageReporter.Unsubscribe();
}
private void OnNewMessageReceived(object sender, MessageEventArgs e)
{
if (!mSubscribeAll && !mMessages.Contains(e.Message))
return;
string message = "Message|" +
$"{e.Time}|" +
$"{e.Text};
try
{
Console.WriteLine(message);
}
catch { }
}
}
What I am trying to achieve is skipping notifications or receiving data for X milliseconds after sending the last message and afterward send the newest received message. I tried sleeping the observers and the provider but it just increased the delay. I think I am missing something and any suggestion would be appreciated.